<commit_before>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

bitflags!{
    flags ProtFlags : libc::c_int {
        const PROT_NONE      = libc::PROT_NONE,
        const PROT_READ      = libc::PROT_READ,
        const PROT_WRITE     = libc::PROT_WRITE,
        const PROT_EXEC      = libc::PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSDOWN = libc::PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSUP   = libc::PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE       = libc::MAP_FILE,
            const MAP_SHARED     = libc::MAP_SHARED,
            const MAP_PRIVATE    = libc::MAP_PRIVATE,
            const MAP_FIXED      = libc::MAP_FIXED,
            const MAP_ANON       = libc::MAP_ANON,
            const MAP_ANONYMOUS  = libc::MAP_ANON,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            const MAP_32BIT      = libc::MAP_32BIT,
            const MAP_GROWSDOWN  = libc::MAP_GROWSDOWN,
            const MAP_DENYWRITE  = libc::MAP_DENYWRITE,
            const MAP_EXECUTABLE = libc::MAP_EXECUTABLE,
            const MAP_LOCKED     = libc::MAP_LOCKED,
            const MAP_NORESERVE  = libc::MAP_NORESERVE,
            const MAP_POPULATE   = libc::MAP_POPULATE,
            const MAP_NONBLOCK   = libc::MAP_NONBLOCK,
            const MAP_STACK      = libc::MAP_STACK,
            const MAP_HUGETLB    = libc::MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC,
            const MS_INVALIDATE = libc::MS_INVALIDATE,
            const MS_SYNC       = libc::MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE    = libc::MAP_FILE,
            const MAP_SHARED  = libc::MAP_SHARED,
            const MAP_PRIVATE = libc::MAP_PRIVATE,
            const MAP_FIXED   = libc::MAP_FIXED,
            const MAP_ANON    = libc::MAP_ANON,
            const MAP_NOCACHE = libc::MAP_NOCACHE,
            const MAP_JIT     = libc::MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            const MS_KILLPAGES  = libc::MS_KILLPAGES, /* invalidate pages, leave mapped */
            const MS_DEACTIVATE = libc::MS_DEACTIVATE, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE         = libc::MAP_FILE,
            const MAP_SHARED       = libc::MAP_SHARED,
            const MAP_PRIVATE      = libc::MAP_PRIVATE,
            const MAP_FIXED        = libc::MAP_FIXED,
            const MAP_RENAME       = libc::MAP_RENAME,
            const MAP_NORESERVE    = libc::MAP_NORESERVE,
            const MAP_HASSEMAPHORE = libc::MAP_HASSEMAPHORE,
            #[cfg(not(target_os = "openbsd"))]
            const MAP_STACK        = libc::MAP_STACK,
            #[cfg(target_os = "netbsd")]
            const MAP_WIRED        = libc::MAP_WIRED,
            const MAP_NOSYNC       = libc::MAP_NOSYNC,
            const MAP_ANON         = libc::MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munlock(addr, length) }).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = unsafe { ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset) };

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munmap(addr, len) }).map(drop)
}

pub fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(unsafe { ffi::madvise(addr, length, advise) }).map(drop)
}

pub fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(unsafe { ffi::msync(addr, length, flags.bits()) }).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<commit_msg>Limit MAP_NOSYNC flag to FreeBSD kin<commit_after>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

bitflags!{
    flags ProtFlags : libc::c_int {
        const PROT_NONE      = libc::PROT_NONE,
        const PROT_READ      = libc::PROT_READ,
        const PROT_WRITE     = libc::PROT_WRITE,
        const PROT_EXEC      = libc::PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSDOWN = libc::PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSUP   = libc::PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE       = libc::MAP_FILE,
            const MAP_SHARED     = libc::MAP_SHARED,
            const MAP_PRIVATE    = libc::MAP_PRIVATE,
            const MAP_FIXED      = libc::MAP_FIXED,
            const MAP_ANON       = libc::MAP_ANON,
            const MAP_ANONYMOUS  = libc::MAP_ANON,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            const MAP_32BIT      = libc::MAP_32BIT,
            const MAP_GROWSDOWN  = libc::MAP_GROWSDOWN,
            const MAP_DENYWRITE  = libc::MAP_DENYWRITE,
            const MAP_EXECUTABLE = libc::MAP_EXECUTABLE,
            const MAP_LOCKED     = libc::MAP_LOCKED,
            const MAP_NORESERVE  = libc::MAP_NORESERVE,
            const MAP_POPULATE   = libc::MAP_POPULATE,
            const MAP_NONBLOCK   = libc::MAP_NONBLOCK,
            const MAP_STACK      = libc::MAP_STACK,
            const MAP_HUGETLB    = libc::MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC,
            const MS_INVALIDATE = libc::MS_INVALIDATE,
            const MS_SYNC       = libc::MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE    = libc::MAP_FILE,
            const MAP_SHARED  = libc::MAP_SHARED,
            const MAP_PRIVATE = libc::MAP_PRIVATE,
            const MAP_FIXED   = libc::MAP_FIXED,
            const MAP_ANON    = libc::MAP_ANON,
            const MAP_NOCACHE = libc::MAP_NOCACHE,
            const MAP_JIT     = libc::MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            const MS_KILLPAGES  = libc::MS_KILLPAGES, /* invalidate pages, leave mapped */
            const MS_DEACTIVATE = libc::MS_DEACTIVATE, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE         = libc::MAP_FILE,
            const MAP_SHARED       = libc::MAP_SHARED,
            const MAP_PRIVATE      = libc::MAP_PRIVATE,
            const MAP_FIXED        = libc::MAP_FIXED,
            const MAP_RENAME       = libc::MAP_RENAME,
            const MAP_NORESERVE    = libc::MAP_NORESERVE,
            const MAP_HASSEMAPHORE = libc::MAP_HASSEMAPHORE,
            #[cfg(not(target_os = "openbsd"))]
            const MAP_STACK        = libc::MAP_STACK,
            #[cfg(target_os = "netbsd")]
            const MAP_WIRED        = libc::MAP_WIRED,
            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
            const MAP_NOSYNC       = libc::MAP_NOSYNC,
            const MAP_ANON         = libc::MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munlock(addr, length) }).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = unsafe { ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset) };

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munmap(addr, len) }).map(drop)
}

pub fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(unsafe { ffi::madvise(addr, length, advise) }).map(drop)
}

pub fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(unsafe { ffi::msync(addr, length, flags.bits()) }).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;

type WordCell = Rc<RefCell<Word>>;
type AuthorCell = Rc<RefCell<Author>>;
type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;

const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

struct Lexicon {
    words: BTreeMap<&'static str, WordCell>,
    authors: BTreeMap<&'static str, AuthorCell>,
    sources: BTreeMap<&'static str, SourceCell>,
    conversations: Vec<ConversationCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl Lexicon {
    fn tell(source: SourceCell, author: &str, message: &str) -> Option<String> {
        None
    }
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

struct Author {
    name: String,
}

struct Source {
    name: String,
    messages: u64,
}

struct MessageWord {
    word: WordCell,
    category: CategoryCell,
}

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    words: Vec<MessageWord>,
}

struct WordInstance {
    word: WordCell,
    message: MessageCell,
    index: usize,
}

struct Category {
    instances: Vec<WordInstance>,
    subcategories: Vec<CategoryCell>,
}

struct Word {
    name: String,
    instances: Vec<WordInstance>,
}
<commit_msg>add supercategory field to category<commit_after>use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;

type WordCell = Rc<RefCell<Word>>;
type AuthorCell = Rc<RefCell<Author>>;
type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

struct Lexicon {
    words: BTreeMap<&'static str, WordCell>,
    authors: BTreeMap<&'static str, AuthorCell>,
    sources: BTreeMap<&'static str, SourceCell>,
    conversations: Vec<ConversationCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl Lexicon {
    fn tell(source: SourceCell, author: &str, message: &str) -> Option<String> {
        None
    }
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

struct Author {
    name: String,
}

struct Source {
    name: String,
    messages: u64,
}

struct MessageWord {
    word: WordCell,
    category: CategoryCell,
}

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    words: Vec<MessageWord>,
}

struct WordInstance {
    word: WordCell,
    message: MessageCell,
    index: usize,
}

struct Category {
    supercategory: Option<CategoryCell>,
    instances: Vec<WordInstance>,
    subcategories: Vec<CategoryCell>,
}

struct Word {
    name: String,
    instances: Vec<WordInstance>,
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum Player {
    A,
    B,
    C,
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealer: u8) {
    let mut cards: Vec<u8> = Vec::new();
    for n in 0..32 {
        cards.push(n);
    }
    // print clubs
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    for n in 0..8 {
        match n {
            0 => {
                let mut ace = "A".to_string();
                ace.push_str(club);
                print!("{} ", Black.bold().paint(&ace));
            },
            1 => {
                let mut ten = "10".to_string();
                ten.push_str(club);
                print!("{} ", Black.bold().paint(&ten));
            },
            2 => {
                let mut king = "K".to_string();
                king.push_str(club);
                print!("{} ", Black.bold().paint(&king));
            },
            3 => {
                let mut queen = "Q".to_string();
                queen.push_str(club);
                print!("{} ", Black.bold().paint(&queen));
            },
            4 => {
                let mut jack = "J".to_string();
                jack.push_str(club);
                print!("{} ", Black.bold().paint(&jack));
            },
            5 => {
                let mut nine = "9".to_string();
                nine.push_str(club);
                print!("{} ", Black.bold().paint(&nine));
            },
            6 => {
                let mut eight = "8".to_string();
                eight.push_str(club);
                print!("{} ", Black.bold().paint(&eight));
            },
            7 => {
                let mut seven = "7".to_string();
                seven.push_str(club);
                print!("{} ", Black.bold().paint(&seven));
            },
            _ => panic!("Unknown card"),
        }
    };
    println!("");
    for n in 8..16 {
        match n {
            8 => {
                let mut ace = "A".to_string();
                ace.push_str(spade);
                print!("{} ", Green.bold().paint(&ace));
            },
            9 => {
                let mut ten = "10".to_string();
                ten.push_str(spade);
                print!("{} ", Green.bold().paint(&ten));
            },
            10 => {
                let mut king = "K".to_string();
                king.push_str(spade);
                print!("{} ", Green.bold().paint(&king));
            },
            11 => {
                let mut queen = "Q".to_string();
                queen.push_str(spade);
                print!("{} ", Green.bold().paint(&queen));
            },
            12 => {
                let mut jack = "J".to_string();
                jack.push_str(spade);
                print!("{} ", Green.bold().paint(&jack));
            },
            13 => {
                let mut nine = "9".to_string();
                nine.push_str(spade);
                print!("{} ", Green.bold().paint(&nine));
            },
            14 => {
                let mut eight = "8".to_string();
                eight.push_str(spade);
                print!("{} ", Green.bold().paint(&eight));
            },
            15 => {
                let mut seven = "7".to_string();
                seven.push_str(spade);
                print!("{} ", Green.bold().paint(&seven));
            },
            _ => panic!("Unknown card"),
        }
    };
    println!("");
    for n in 16..24 {
        match n {
            16 => {
                let mut ace = "A".to_string();
                ace.push_str(heart);
                print!("{} ", Red.bold().paint(&ace));
            },
            17 => {
                let mut ten = "10".to_string();
                ten.push_str(heart);
                print!("{} ", Red.bold().paint(&ten));
            },
            18 => {
                let mut king = "K".to_string();
                king.push_str(heart);
                print!("{} ", Red.bold().paint(&king));
            },
            19 => {
                let mut queen = "Q".to_string();
                queen.push_str(heart);
                print!("{} ", Red.bold().paint(&queen));
            },
            20 => {
                let mut jack = "J".to_string();
                jack.push_str(heart);
                print!("{} ", Red.bold().paint(&jack));
            },
            21 => {
                let mut nine = "9".to_string();
                nine.push_str(heart);
                print!("{} ", Red.bold().paint(&nine));
            },
            22 => {
                let mut eight = "8".to_string();
                eight.push_str(heart);
                print!("{} ", Red.bold().paint(&eight));
            },
            23 => {
                let mut seven = "7".to_string();
                seven.push_str(heart);
                print!("{} ", Red.bold().paint(&seven));
            },
            _ => panic!("Unknown card"),
        }
    };
    println!("");
    for n in 24..32 {
        match n {
            24 => {
                let mut ace = "A".to_string();
                ace.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&ace));
            },
            25 => {
                let mut ten = "10".to_string();
                ten.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&ten));
            },
            26 => {
                let mut king = "K".to_string();
                king.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&king));
            },
            27 => {
                let mut queen = "Q".to_string();
                queen.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&queen));
            },
            28 => {
                let mut jack = "J".to_string();
                jack.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&jack));
            },
            29 => {
                let mut nine = "9".to_string();
                nine.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&nine));
            },
            30 => {
                let mut eight = "8".to_string();
                eight.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&eight));
            },
            31 => {
                let mut seven = "7".to_string();
                seven.push_str(diamond);
                print!("{} ", Yellow.bold().paint(&seven));
            },
            _ => panic!("Unknown card"),
        }
    };
    println!("");
}

fn main() {
    // randomly select player
    let player_number: u8 = rand::thread_rng().gen_range(0, 3);
    match player_number {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Unknown player {}", player_number),
    }
    loop {
        // player player_number is dealing
        deal(player_number);
        // bid
        let (player, bid) = bid(player_number);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<commit_msg>Print sorted cards (before shuffling).<commit_after>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum Player {
    A,
    B,
    C,
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealer: u8) {
    let mut cards: Vec<u8> = Vec::new();
    // print sorted cards
    for n in 0..32 {
        cards.push(n);
    }
    for n in 0..8 {
        print_card(n);
    };
    println!("");
    for n in 8..16 {
        print_card(n);
    }
    println!("");
    for n in 16..24 {
        print_card(n);
    };
    println!("");
    for n in 24..32 {
        print_card(n);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = "A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = "K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = "Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = "J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = "9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = "8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = "7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = "A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = "K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = "Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = "J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = "9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = "8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = "7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = "A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = "K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = "Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = "J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = "9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = "8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = "7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = "A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = "K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = "Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = "J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = "9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = "8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = "7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_number: u8 = rand::thread_rng().gen_range(0, 3);
    match player_number {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Unknown player {}", player_number),
    }
    loop {
        // player player_number is dealing
        deal(player_number);
        // bid
        let (player, bid) = bid(player_number);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>examples/id3_sample.rs: g/c: tabs<commit_after><|endoftext|>


<commit_before><commit_msg>Fix apt-get for older ubuntu<commit_after><|endoftext|>


<commit_before><commit_msg>Removing test.<commit_after><|endoftext|>


<commit_before>fn main() {
    let s = String::from("Hello there");

    let first = first_word(&s);
    println!("First word is: {}", first);
}

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[..i];
        }
    }

    &s[..]
}
<commit_msg>Rewrite function to accept string slice as param so it can handle Strings and string literals<commit_after>fn main() {
    let s = String::from("Hello there");

    let first = first_word(&s[..]);
    println!("First word is: {}", first);
}

fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[..i];
        }
    }

    &s[..]
}
<|endoftext|>


<commit_before>/*!
`ndarray` compability

This adds support for reading data into [`ndarray`][ndarray] array objects. This primarily
enables support for automatically reshaping the resulting arrays to have the dimensionality of
the image that was asked for.

Data is read into the [`ndarray::ArrayD`][arrayd] type. The following methods from
[`FitsHdu`][fits-hdu] are supported:

* [`read_image`][read-image]
* [`read_region`][read-region]
* [`read_row`][read-row]
* [`read_rows`][read-rows]
* [`read_section`][read-section]

## `read_image`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 100);
assert_eq!(dim[1], 100);
assert_eq!(data[[20, 5]], 152);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_region`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 10);
assert_eq!(dim[1], 30);
assert_eq!(data[[5, 10]], 177);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_row`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
assert_eq!(data.ndim(), 1);
assert_eq!(data[20], 156);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_rows`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[1, 52]], 184);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_section`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
use fitsio::errors::Error;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
    Err(Error::Message(msg)) => {
        assert_eq!(
            msg,
            "must request number of pixels exactly divisible by image width".to_string()
        );
    }
    _ => panic!("invalid result"),
}

let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[0, 10]], 160);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

[ndarray]: https://crates.io/crates/ndarray
[arrayd]: https://docs.rs/ndarray/0.11.2/ndarray/type.ArrayD.html
[fits-hdu]: hdu/struct.FitsHdu.html
[read-image]: images/struct.FitsHdu.html#method.read_image
[read-region]: images/struct.FitsHdu.html#method.read_region
[read-row]: images/struct.FitsHdu.html#method.read_row
[read-rows]: images/struct.FitsHdu.html#method.read_rows
[read-section]: images/struct.FitsHdu.html#method.read_section
*/

use errors::Result;
use fitsfile::FitsFile;
use hdu::{FitsHdu, HduInfo};
use images::ReadImage;
use ndarray::{Array, ArrayD};
use std::ops::Range;

impl<T> ReadImage for ArrayD<T>
where
    T: Clone,
    Vec<T>: ReadImage,
{
    fn read_section(fits_file: &mut FitsFile, hdu: &FitsHdu, range: Range<usize>) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                if shape.len() != 2 {
                    return Err("Only 2D images supported for now".into());
                }

                let width = shape[1];

                if range.start % width != 0 {
                    return Err("range must start on row boundary".into());
                }
                let start_pixel = range.start / width;

                let n_pixels_requested = range.end - range.start;
                if n_pixels_requested % width != 0 {
                    return Err(
                        "must request number of pixels exactly divisible by image width".into(),
                    );
                }

                let n_rows = n_pixels_requested / width;
                ReadImage::read_rows(fits_file, hdu, start_pixel, n_rows)
            }
            HduInfo::TableInfo { .. } => {
                return Err("Cannot read image data from a FITS table".into())
            }
            _ => unreachable!(),
        }
    }

    fn read_rows(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        start_row: usize,
        num_rows: usize,
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_rows(fits_file, hdu, start_row, num_rows)?;
        let arr = Array::from_vec(data);
        let row_length = arr.len() / num_rows;
        Ok(arr.into_shape(vec![num_rows, row_length]).unwrap())
    }

    fn read_row(fits_file: &mut FitsFile, hdu: &FitsHdu, row: usize) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_row(fits_file, hdu, row)?;
        let shape = vec![data.len()];
        Ok(Array::from_shape_vec(shape, data).unwrap())
    }

    fn read_region(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        ranges: &[&Range<usize>],
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_region(fits_file, hdu, ranges)?;
        let shape: Vec<usize> = (0..ranges.len())
            .map(|i| ranges[i].end - ranges[i].start)
            .collect();
        let arr = Array::from_shape_vec(shape, data).unwrap();
        Ok(arr)
    }

    fn read_image(fits_file: &mut FitsFile, hdu: &FitsHdu) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                let data: Vec<T> = ReadImage::read_image(fits_file, hdu)?;
                let shape: Vec<usize> = (0..2).map(|i| shape[i]).collect();
                let arr = Array::from_shape_vec(shape, data).unwrap();
                Ok(arr)
            }
            _ => unreachable!(),
        }
    }
}

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

    #[test]
    fn test_read_image() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 100);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[20, 5]], 152);
    }

    #[test]
    fn test_read_rows() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[1, 52]], 184);
    }

    #[test]
    fn test_read_row() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
        assert_eq!(data.ndim(), 1);
        assert_eq!(data[20], 156);
    }

    #[test]
    fn test_read_region() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 10);
        assert_eq!(dim[1], 30);
        assert_eq!(data[[5, 10]], 177);
    }

    #[test]
    fn test_read_section() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
            Err(Error::Message(msg)) => {
                assert_eq!(
                    msg,
                    "must request number of pixels exactly divisible by image width".to_string()
                );
            }
            _ => panic!("invalid result"),
        }

        let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[0, 10]], 160);
    }
}
<commit_msg>Format code as per formatter<commit_after>/*!
`ndarray` compability

This adds support for reading data into [`ndarray`][ndarray] array objects. This primarily
enables support for automatically reshaping the resulting arrays to have the dimensionality of
the image that was asked for.

Data is read into the [`ndarray::ArrayD`][arrayd] type. The following methods from
[`FitsHdu`][fits-hdu] are supported:

* [`read_image`][read-image]
* [`read_region`][read-region]
* [`read_row`][read-row]
* [`read_rows`][read-rows]
* [`read_section`][read-section]

## `read_image`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 100);
assert_eq!(dim[1], 100);
assert_eq!(data[[20, 5]], 152);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_region`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 10);
assert_eq!(dim[1], 30);
assert_eq!(data[[5, 10]], 177);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_row`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
assert_eq!(data.ndim(), 1);
assert_eq!(data[20], 156);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_rows`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[1, 52]], 184);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_section`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
use fitsio::errors::Error;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
    Err(Error::Message(msg)) => {
        assert_eq!(
            msg,
            "must request number of pixels exactly divisible by image width".to_string()
        );
    }
    _ => panic!("invalid result"),
}

let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[0, 10]], 160);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

[ndarray]: https://crates.io/crates/ndarray
[arrayd]: https://docs.rs/ndarray/0.11.2/ndarray/type.ArrayD.html
[fits-hdu]: hdu/struct.FitsHdu.html
[read-image]: images/struct.FitsHdu.html#method.read_image
[read-region]: images/struct.FitsHdu.html#method.read_region
[read-row]: images/struct.FitsHdu.html#method.read_row
[read-rows]: images/struct.FitsHdu.html#method.read_rows
[read-section]: images/struct.FitsHdu.html#method.read_section
*/

use errors::Result;
use fitsfile::FitsFile;
use hdu::{FitsHdu, HduInfo};
use images::ReadImage;
use ndarray::{Array, ArrayD};
use std::ops::Range;

impl<T> ReadImage for ArrayD<T>
where
    T: Clone,
    Vec<T>: ReadImage,
{
    fn read_section(fits_file: &mut FitsFile, hdu: &FitsHdu, range: Range<usize>) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                if shape.len() != 2 {
                    return Err("Only 2D images supported for now".into());
                }

                let width = shape[1];

                if range.start % width != 0 {
                    return Err("range must start on row boundary".into());
                }
                let start_pixel = range.start / width;

                let n_pixels_requested = range.end - range.start;
                if n_pixels_requested % width != 0 {
                    return Err(
                        "must request number of pixels exactly divisible by image width".into(),
                    );
                }

                let n_rows = n_pixels_requested / width;
                ReadImage::read_rows(fits_file, hdu, start_pixel, n_rows)
            }
            HduInfo::TableInfo { .. } => {
                return Err("Cannot read image data from a FITS table".into());
            }
            _ => unreachable!(),
        }
    }

    fn read_rows(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        start_row: usize,
        num_rows: usize,
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_rows(fits_file, hdu, start_row, num_rows)?;
        let arr = Array::from_vec(data);
        let row_length = arr.len() / num_rows;
        Ok(arr.into_shape(vec![num_rows, row_length]).unwrap())
    }

    fn read_row(fits_file: &mut FitsFile, hdu: &FitsHdu, row: usize) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_row(fits_file, hdu, row)?;
        let shape = vec![data.len()];
        Ok(Array::from_shape_vec(shape, data).unwrap())
    }

    fn read_region(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        ranges: &[&Range<usize>],
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_region(fits_file, hdu, ranges)?;
        let shape: Vec<usize> = (0..ranges.len())
            .map(|i| ranges[i].end - ranges[i].start)
            .collect();
        let arr = Array::from_shape_vec(shape, data).unwrap();
        Ok(arr)
    }

    fn read_image(fits_file: &mut FitsFile, hdu: &FitsHdu) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                let data: Vec<T> = ReadImage::read_image(fits_file, hdu)?;
                let shape: Vec<usize> = (0..2).map(|i| shape[i]).collect();
                let arr = Array::from_shape_vec(shape, data).unwrap();
                Ok(arr)
            }
            _ => unreachable!(),
        }
    }
}

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

    #[test]
    fn test_read_image() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 100);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[20, 5]], 152);
    }

    #[test]
    fn test_read_rows() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[1, 52]], 184);
    }

    #[test]
    fn test_read_row() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
        assert_eq!(data.ndim(), 1);
        assert_eq!(data[20], 156);
    }

    #[test]
    fn test_read_region() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 10);
        assert_eq!(dim[1], 30);
        assert_eq!(data[[5, 10]], 177);
    }

    #[test]
    fn test_read_section() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
            Err(Error::Message(msg)) => {
                assert_eq!(
                    msg,
                    "must request number of pixels exactly divisible by image width".to_string()
                );
            }
            _ => panic!("invalid result"),
        }

        let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[0, 10]], 160);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

use std::boxed::Box;
use std::env;
use std::ops::Deref;
use std::panic;
use std::path::Path;
use std::path::PathBuf;

use breakpad_symbols::{HttpSymbolSupplier, SimpleSymbolSupplier, Symbolizer};
use minidump::*;
use minidump_processor::{DwarfSymbolizer, MultiSymbolProvider};

use clap::{crate_authors, crate_version, App, Arg};
use log::error;
use simplelog::{Config, LevelFilter, TermLogger, TerminalMode};

fn print_minidump_process(
    path: &Path,
    symbol_paths: Vec<PathBuf>,
    symbol_urls: Vec<String>,
    symbols_cache: Option<PathBuf>,
    human: bool,
    pretty: bool,
) {
    if let Ok(dump) = Minidump::read_path(path) {
        let mut provider = MultiSymbolProvider::new();

        if let Some(symbols_cache) = symbols_cache {
            provider.add(Box::new(Symbolizer::new(HttpSymbolSupplier::new(
                symbol_urls,
                symbols_cache,
                symbol_paths,
            ))));
        } else if !symbol_paths.is_empty() {
            provider.add(Box::new(Symbolizer::new(SimpleSymbolSupplier::new(
                symbol_paths,
            ))));
        }
        provider.add(Box::new(DwarfSymbolizer::new()));

        match minidump_processor::process_minidump(&dump, &provider) {
            Ok(state) => {
                let mut stdout = std::io::stdout();
                if human {
                    state.print(&mut stdout).unwrap();
                } else {
                    state.print_json(&mut stdout, pretty).unwrap();
                }
            }
            Err(err) => {
                eprintln!("Error processing dump: {:?}", err);
                std::process::exit(1);
            }
        }
    } else {
        eprintln!("Error reading dump");
        std::process::exit(1);
    }
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let matches = App::new("minidump_stackwalk")
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about("Analyzes minidumps and produces a machine-readable JSON report")
        .arg(
            Arg::with_name("human")
                .help("Emit a human-readable report instead")
                .long("human")
        )
        .arg(
            Arg::with_name("pretty")
                .help("Pretty-print JSON output.")
                .long("pretty")
        )
        .arg(
            Arg::with_name("pipe-dump")
                .help("Produce pipe-delimited output in addition to JSON output")
                .long("pipe-dump")
        )
        .arg(
            Arg::with_name("verbose")
                .help("Set the level of verbosity (off, error (default), warn, info, debug, trace)")
                .long("verbose")
                .default_value("error")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("raw-json")
                .help("An input file with the raw annotations as JSON")
                .long("raw-json")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("symbols-url")
                .help("A base URL from which URLs to symbol files can be constructed")
                .multiple(true)
                .long("symbols-url")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("symbols-cache")
                .help("A directory in which downloaded symbols can be stored")
                .long("symbols-cache")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("symbols-tmp")
                .help("A directory to use as temp space for downloading symbols. Must be on the same filesystem as symbols-cache.")
                .long("symbols-tmp")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("minidump")
                .help("Path to minidump file")
                .required(true)
                .takes_value(true)
        )
        .arg(
            Arg::with_name("symbols-path")
                .help("Path to symbol file")
                .multiple(true)
                .takes_value(true)
        )
        .get_matches();

    let verbosity = match matches.value_of("verbose").unwrap() {
        "off" => LevelFilter::Off,
        "warn" => LevelFilter::Warn,
        "info" => LevelFilter::Info,
        "debug" => LevelFilter::Debug,
        "trace" => LevelFilter::Trace,
        _ => LevelFilter::Error,
    };

    // Init the logger
    let _ = TermLogger::init(verbosity, Config::default(), TerminalMode::Stderr);

    // Set a panic hook to redirect to the logger
    panic::set_hook(Box::new(|panic_info| {
        let (filename, line) = panic_info
            .location()
            .map(|loc| (loc.file(), loc.line()))
            .unwrap_or(("<unknown>", 0));
        let cause = panic_info
            .payload()
            .downcast_ref::<String>()
            .map(String::deref)
            .unwrap_or_else(|| {
                panic_info
                    .payload()
                    .downcast_ref::<&str>()
                    .copied()
                    .unwrap_or("<cause unknown>")
            });
        error!("A panic occurred at {}:{}: {}", filename, line, cause);
    }));

    // All options the original minidump-stackwalk has, stubbed out for when we need them:
    let _pipe = matches.is_present("pipe-dump");
    let _json_path = matches.value_of_os("raw-json").map(Path::new);
    let symbols_cache = matches
        .value_of_os("symbols-cache")
        .map(|os_str| Path::new(os_str).to_owned());
    let _symbols_tmp = matches.value_of_os("symbols-tmp").map(Path::new);
    let symbols_urls = matches
        .values_of("symbols-url")
        .map(|v| v.map(String::from).collect::<Vec<_>>())
        .unwrap_or_else(Vec::new);

    let pretty = matches.is_present("pretty");
    let human = matches.is_present("human");

    let minidump_path = matches.value_of_os("minidump").map(Path::new).unwrap();
    let symbols_paths = matches
        .values_of_os("symbols-path")
        .map(|v| {
            v.map(|os_str| Path::new(os_str).to_owned())
                .collect::<Vec<_>>()
        })
        .unwrap_or_else(Vec::new);

    if symbols_urls.is_empty() != symbols_cache.is_none() {
        eprintln!("You must specify both --symbols-url and --symbols-cache when using one of these options");
        std::process::exit(1);
    }

    print_minidump_process(
        minidump_path,
        symbols_paths,
        symbols_urls,
        symbols_cache,
        human,
        pretty,
    );
}
<commit_msg>Minor cleanups to CLI frontend<commit_after>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

use std::boxed::Box;
use std::env;
use std::ops::Deref;
use std::panic;
use std::path::Path;
use std::path::PathBuf;

use breakpad_symbols::{HttpSymbolSupplier, SimpleSymbolSupplier, Symbolizer};
use minidump::*;
use minidump_processor::{DwarfSymbolizer, MultiSymbolProvider};

use clap::{crate_authors, crate_version, App, Arg};
use log::error;
use simplelog::{Config, LevelFilter, TermLogger, TerminalMode};

fn print_minidump_process(
    path: &Path,
    symbol_paths: Vec<PathBuf>,
    symbol_urls: Vec<String>,
    symbols_cache: Option<PathBuf>,
    human: bool,
    pretty: bool,
) {
    if let Ok(dump) = Minidump::read_path(path) {
        let mut provider = MultiSymbolProvider::new();

        if let Some(symbols_cache) = symbols_cache {
            provider.add(Box::new(Symbolizer::new(HttpSymbolSupplier::new(
                symbol_urls,
                symbols_cache,
                symbol_paths,
            ))));
        } else if !symbol_paths.is_empty() {
            provider.add(Box::new(Symbolizer::new(SimpleSymbolSupplier::new(
                symbol_paths,
            ))));
        }
        provider.add(Box::new(DwarfSymbolizer::new()));

        match minidump_processor::process_minidump(&dump, &provider) {
            Ok(state) => {
                let mut stdout = std::io::stdout();
                if human {
                    state.print(&mut stdout).unwrap();
                } else {
                    state.print_json(&mut stdout, pretty).unwrap();
                }
            }
            Err(err) => {
                eprintln!("Error processing dump: {:?}", err);
                std::process::exit(1);
            }
        }
    } else {
        eprintln!("Error reading dump");
        std::process::exit(1);
    }
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let matches = App::new("minidump_stackwalk")
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about("Analyzes minidumps and produces a machine-readable JSON report")
        .arg(
            Arg::with_name("human")
                .help("Emit a human-readable report instead")
                .long("human")
        )
        .arg(
            Arg::with_name("pretty")
                .help("Pretty-print JSON output.")
                .long("pretty")
        )
        .arg(
            Arg::with_name("verbose")
                .help("Set the level of verbosity (off, error (default), warn, info, debug, trace)")
                .long("verbose")
                .default_value("error")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("raw-json")
                .help("An input JSON file with the extra information (not yet implemented)")
                .long("raw-json")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("symbols-url")
                .help("A base URL from which URLs to symbol files can be constructed")
                .multiple(true)
                .long("symbols-url")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("symbols-cache")
                .help("A directory in which downloaded symbols can be stored")
                .long("symbols-cache")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("symbols-tmp")
                .help("A directory to use as temp space for downloading symbols. Must be on the same filesystem as symbols-cache. (not yet implemented)")
                .long("symbols-tmp")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("minidump")
                .help("Path to the minidump file")
                .required(true)
                .takes_value(true)
        )
        .arg(
            Arg::with_name("symbols-path")
                .help("Path to a symbol file")
                .multiple(true)
                .takes_value(true)
        )
        .get_matches();

    let verbosity = match matches.value_of("verbose").unwrap() {
        "off" => LevelFilter::Off,
        "warn" => LevelFilter::Warn,
        "info" => LevelFilter::Info,
        "debug" => LevelFilter::Debug,
        "trace" => LevelFilter::Trace,
        _ => LevelFilter::Error,
    };

    // Init the logger
    let _ = TermLogger::init(verbosity, Config::default(), TerminalMode::Stderr);

    // Set a panic hook to redirect to the logger
    panic::set_hook(Box::new(|panic_info| {
        let (filename, line) = panic_info
            .location()
            .map(|loc| (loc.file(), loc.line()))
            .unwrap_or(("<unknown>", 0));
        let cause = panic_info
            .payload()
            .downcast_ref::<String>()
            .map(String::deref)
            .unwrap_or_else(|| {
                panic_info
                    .payload()
                    .downcast_ref::<&str>()
                    .copied()
                    .unwrap_or("<cause unknown>")
            });
        error!("A panic occurred at {}:{}: {}", filename, line, cause);
    }));

    // All options the original minidump-stackwalk has, stubbed out for when we need them:
    let _json_path = matches.value_of_os("raw-json").map(Path::new);
    let symbols_cache = matches
        .value_of_os("symbols-cache")
        .map(|os_str| Path::new(os_str).to_owned());
    let _symbols_tmp = matches.value_of_os("symbols-tmp").map(Path::new);
    let symbols_urls = matches
        .values_of("symbols-url")
        .map(|v| v.map(String::from).collect::<Vec<_>>())
        .unwrap_or_else(Vec::new);

    let pretty = matches.is_present("pretty");
    let human = matches.is_present("human");

    let minidump_path = matches.value_of_os("minidump").map(Path::new).unwrap();
    let symbols_paths = matches
        .values_of_os("symbols-path")
        .map(|v| {
            v.map(|os_str| Path::new(os_str).to_owned())
                .collect::<Vec<_>>()
        })
        .unwrap_or_else(Vec::new);

    if pretty && human {
        eprintln!("Humans must be hideous! (The --pretty and --human flags cannot both be set)");
        std::process::exit(1);
    }

    if symbols_urls.is_empty() != symbols_cache.is_none() {
        eprintln!("You must specify both --symbols-url and --symbols-cache when using one of these options");
        std::process::exit(1);
    }

    print_minidump_process(
        minidump_path,
        symbols_paths,
        symbols_urls,
        symbols_cache,
        human,
        pretty,
    );
}
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::error::{Error, Result};
use base::{
    error, warn, wrap_descriptor, AsRawDescriptor, Descriptor, EpollContext, EpollEvents, Event,
    RawDescriptor, WatchingEvents,
};
use std::collections::BTreeMap;
use std::mem::drop;
use std::sync::{Arc, Weak};
use std::thread;
use sync::Mutex;

/// A fail handle will do the clean up when we cannot recover from some error.
pub trait FailHandle: Send + Sync {
    /// Fail the code.
    fn fail(&self);
    /// Returns true if already failed.
    fn failed(&self) -> bool;
}

impl FailHandle for Option<Arc<dyn FailHandle>> {
    fn fail(&self) {
        match self {
            Some(handle) => handle.fail(),
            None => error!("event loop trying to fail without a fail handle"),
        }
    }

    fn failed(&self) -> bool {
        match self {
            Some(handle) => handle.failed(),
            None => false,
        }
    }
}

/// EpollEventLoop is an event loop blocked on a set of fds. When a monitered events is triggered,
/// event loop will invoke the mapped handler.
pub struct EventLoop {
    fail_handle: Option<Arc<dyn FailHandle>>,
    poll_ctx: Arc<EpollContext<Descriptor>>,
    handlers: Arc<Mutex<BTreeMap<RawDescriptor, Weak<dyn EventHandler>>>>,
    stop_evt: Event,
}

/// Interface for event handler.
pub trait EventHandler: Send + Sync {
    fn on_event(&self) -> std::result::Result<(), ()>;
}

impl EventLoop {
    /// Start an event loop. An optional fail handle could be passed to the event loop.
    pub fn start(
        name: String,
        fail_handle: Option<Arc<dyn FailHandle>>,
    ) -> Result<(EventLoop, thread::JoinHandle<()>)> {
        let (self_stop_evt, stop_evt) = Event::new()
            .and_then(|e| Ok((e.try_clone()?, e)))
            .map_err(Error::CreateEvent)?;

        let fd_callbacks: Arc<Mutex<BTreeMap<RawDescriptor, Weak<dyn EventHandler>>>> =
            Arc::new(Mutex::new(BTreeMap::new()));
        let poll_ctx: EpollContext<Descriptor> = EpollContext::new()
            .and_then(|pc| {
                pc.add(
                    &wrap_descriptor(&stop_evt),
                    Descriptor(stop_evt.as_raw_descriptor()),
                )
                .and(Ok(pc))
            })
            .map_err(Error::CreateWaitContext)?;

        let poll_ctx = Arc::new(poll_ctx);
        let event_loop = EventLoop {
            fail_handle: fail_handle.clone(),
            poll_ctx: poll_ctx.clone(),
            handlers: fd_callbacks.clone(),
            stop_evt: self_stop_evt,
        };

        let handle = thread::Builder::new()
            .name(name)
            .spawn(move || {
                let event_loop = EpollEvents::new();
                loop {
                    if fail_handle.failed() {
                        error!("xhci controller already failed, stopping event ring");
                        return;
                    }
                    let events = match poll_ctx.wait(&event_loop) {
                        Ok(events) => events,
                        Err(e) => {
                            error!("cannot poll {:?}", e);
                            fail_handle.fail();
                            return;
                        }
                    };
                    for event in &events {
                        if event.token().as_raw_descriptor() == stop_evt.as_raw_descriptor() {
                            return;
                        } else {
                            let fd = event.token().as_raw_descriptor();
                            let mut locked = fd_callbacks.lock();
                            let weak_handler = match locked.get(&fd) {
                                Some(cb) => cb.clone(),
                                None => {
                                    warn!("callback for fd {} already removed", fd);
                                    continue;
                                }
                            };
                            match weak_handler.upgrade() {
                                Some(handler) => {
                                    // Drop lock before triggering the event.
                                    drop(locked);
                                    match handler.on_event() {
                                        Ok(()) => {}
                                        Err(_) => {
                                            error!("event loop stopping due to handle event error");
                                            fail_handle.fail();
                                            return;
                                        }
                                    };
                                }
                                // If the handler is already gone, we remove the fd.
                                None => {
                                    let _ = poll_ctx.delete(&Descriptor(fd));
                                    if locked.remove(&fd).is_none() {
                                        error!("fail to remove handler for file descriptor {}", fd);
                                    }
                                }
                            };
                        }
                    }
                }
            })
            .map_err(Error::StartThread)?;

        Ok((event_loop, handle))
    }

    /// Add a new event to event loop. The event handler will be invoked when `event` happens on
    /// `descriptor`.
    ///
    /// If the same `descriptor` is added multiple times, the old handler will be replaced.
    /// EventLoop will not keep `handler` alive, if handler is dropped when `event` is triggered,
    /// the event will be removed.
    pub fn add_event(
        &self,
        descriptor: &dyn AsRawDescriptor,
        events: WatchingEvents,
        handler: Weak<dyn EventHandler>,
    ) -> Result<()> {
        if self.fail_handle.failed() {
            return Err(Error::EventLoopAlreadyFailed);
        }
        self.handlers
            .lock()
            .insert(descriptor.as_raw_descriptor(), handler);
        // This might fail due to epoll syscall. Check epoll_ctl(2).
        self.poll_ctx
            .add_fd_with_events(
                &wrap_descriptor(descriptor),
                events,
                Descriptor(descriptor.as_raw_descriptor()),
            )
            .map_err(Error::WaitContextAddDescriptor)
    }

    /// Removes event for this `descriptor`. This function returns false if it fails.
    ///
    /// EventLoop does not guarantee all events for `descriptor` is handled.
    pub fn remove_event_for_fd(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {
        if self.fail_handle.failed() {
            return Err(Error::EventLoopAlreadyFailed);
        }
        // This might fail due to epoll syscall. Check epoll_ctl(2).
        self.poll_ctx
            .delete(&wrap_descriptor(descriptor))
            .map_err(Error::WaitContextDeleteDescriptor)?;
        self.handlers.lock().remove(&descriptor.as_raw_descriptor());
        Ok(())
    }

    /// Stops this event loop asynchronously. Previous events might not be handled.
    pub fn stop(&self) {
        match self.stop_evt.write(1) {
            Ok(_) => {}
            Err(_) => {
                error!("fail to send event loop stop event, it might already stopped");
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use base::Event;
    use std::sync::{Arc, Condvar, Mutex};

    struct EventLoopTestHandler {
        val: Mutex<u8>,
        cvar: Condvar,
        evt: Event,
    }

    impl EventHandler for EventLoopTestHandler {
        fn on_event(&self) -> std::result::Result<(), ()> {
            self.evt.read().unwrap();
            *self.val.lock().unwrap() += 1;
            self.cvar.notify_one();
            Ok(())
        }
    }

    #[test]
    fn event_loop_test() {
        let (l, j) = EventLoop::start("test".to_string(), None).unwrap();
        let (self_evt, evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
            Ok(v) => v,
            Err(e) => {
                error!("failed creating Event pair: {:?}", e);
                return;
            }
        };
        let h = Arc::new(EventLoopTestHandler {
            val: Mutex::new(0),
            cvar: Condvar::new(),
            evt,
        });
        let t: Arc<dyn EventHandler> = h.clone();
        l.add_event(
            &h.evt,
            WatchingEvents::empty().set_read(),
            Arc::downgrade(&t),
        )
        .unwrap();
        self_evt.write(1).unwrap();
        let _ = h.cvar.wait(h.val.lock().unwrap()).unwrap();
        l.stop();
        j.join().unwrap();
        assert_eq!(*(h.val.lock().unwrap()), 1);
    }
}
<commit_msg>devices: Fix racy event_loop_test<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::error::{Error, Result};
use base::{
    error, warn, wrap_descriptor, AsRawDescriptor, Descriptor, EpollContext, EpollEvents, Event,
    RawDescriptor, WatchingEvents,
};
use std::collections::BTreeMap;
use std::mem::drop;
use std::sync::{Arc, Weak};
use std::thread;
use sync::Mutex;

/// A fail handle will do the clean up when we cannot recover from some error.
pub trait FailHandle: Send + Sync {
    /// Fail the code.
    fn fail(&self);
    /// Returns true if already failed.
    fn failed(&self) -> bool;
}

impl FailHandle for Option<Arc<dyn FailHandle>> {
    fn fail(&self) {
        match self {
            Some(handle) => handle.fail(),
            None => error!("event loop trying to fail without a fail handle"),
        }
    }

    fn failed(&self) -> bool {
        match self {
            Some(handle) => handle.failed(),
            None => false,
        }
    }
}

/// EpollEventLoop is an event loop blocked on a set of fds. When a monitered events is triggered,
/// event loop will invoke the mapped handler.
pub struct EventLoop {
    fail_handle: Option<Arc<dyn FailHandle>>,
    poll_ctx: Arc<EpollContext<Descriptor>>,
    handlers: Arc<Mutex<BTreeMap<RawDescriptor, Weak<dyn EventHandler>>>>,
    stop_evt: Event,
}

/// Interface for event handler.
pub trait EventHandler: Send + Sync {
    fn on_event(&self) -> std::result::Result<(), ()>;
}

impl EventLoop {
    /// Start an event loop. An optional fail handle could be passed to the event loop.
    pub fn start(
        name: String,
        fail_handle: Option<Arc<dyn FailHandle>>,
    ) -> Result<(EventLoop, thread::JoinHandle<()>)> {
        let (self_stop_evt, stop_evt) = Event::new()
            .and_then(|e| Ok((e.try_clone()?, e)))
            .map_err(Error::CreateEvent)?;

        let fd_callbacks: Arc<Mutex<BTreeMap<RawDescriptor, Weak<dyn EventHandler>>>> =
            Arc::new(Mutex::new(BTreeMap::new()));
        let poll_ctx: EpollContext<Descriptor> = EpollContext::new()
            .and_then(|pc| {
                pc.add(
                    &wrap_descriptor(&stop_evt),
                    Descriptor(stop_evt.as_raw_descriptor()),
                )
                .and(Ok(pc))
            })
            .map_err(Error::CreateWaitContext)?;

        let poll_ctx = Arc::new(poll_ctx);
        let event_loop = EventLoop {
            fail_handle: fail_handle.clone(),
            poll_ctx: poll_ctx.clone(),
            handlers: fd_callbacks.clone(),
            stop_evt: self_stop_evt,
        };

        let handle = thread::Builder::new()
            .name(name)
            .spawn(move || {
                let event_loop = EpollEvents::new();
                loop {
                    if fail_handle.failed() {
                        error!("xhci controller already failed, stopping event ring");
                        return;
                    }
                    let events = match poll_ctx.wait(&event_loop) {
                        Ok(events) => events,
                        Err(e) => {
                            error!("cannot poll {:?}", e);
                            fail_handle.fail();
                            return;
                        }
                    };
                    for event in &events {
                        if event.token().as_raw_descriptor() == stop_evt.as_raw_descriptor() {
                            return;
                        } else {
                            let fd = event.token().as_raw_descriptor();
                            let mut locked = fd_callbacks.lock();
                            let weak_handler = match locked.get(&fd) {
                                Some(cb) => cb.clone(),
                                None => {
                                    warn!("callback for fd {} already removed", fd);
                                    continue;
                                }
                            };
                            match weak_handler.upgrade() {
                                Some(handler) => {
                                    // Drop lock before triggering the event.
                                    drop(locked);
                                    match handler.on_event() {
                                        Ok(()) => {}
                                        Err(_) => {
                                            error!("event loop stopping due to handle event error");
                                            fail_handle.fail();
                                            return;
                                        }
                                    };
                                }
                                // If the handler is already gone, we remove the fd.
                                None => {
                                    let _ = poll_ctx.delete(&Descriptor(fd));
                                    if locked.remove(&fd).is_none() {
                                        error!("fail to remove handler for file descriptor {}", fd);
                                    }
                                }
                            };
                        }
                    }
                }
            })
            .map_err(Error::StartThread)?;

        Ok((event_loop, handle))
    }

    /// Add a new event to event loop. The event handler will be invoked when `event` happens on
    /// `descriptor`.
    ///
    /// If the same `descriptor` is added multiple times, the old handler will be replaced.
    /// EventLoop will not keep `handler` alive, if handler is dropped when `event` is triggered,
    /// the event will be removed.
    pub fn add_event(
        &self,
        descriptor: &dyn AsRawDescriptor,
        events: WatchingEvents,
        handler: Weak<dyn EventHandler>,
    ) -> Result<()> {
        if self.fail_handle.failed() {
            return Err(Error::EventLoopAlreadyFailed);
        }
        self.handlers
            .lock()
            .insert(descriptor.as_raw_descriptor(), handler);
        // This might fail due to epoll syscall. Check epoll_ctl(2).
        self.poll_ctx
            .add_fd_with_events(
                &wrap_descriptor(descriptor),
                events,
                Descriptor(descriptor.as_raw_descriptor()),
            )
            .map_err(Error::WaitContextAddDescriptor)
    }

    /// Removes event for this `descriptor`. This function returns false if it fails.
    ///
    /// EventLoop does not guarantee all events for `descriptor` is handled.
    pub fn remove_event_for_fd(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {
        if self.fail_handle.failed() {
            return Err(Error::EventLoopAlreadyFailed);
        }
        // This might fail due to epoll syscall. Check epoll_ctl(2).
        self.poll_ctx
            .delete(&wrap_descriptor(descriptor))
            .map_err(Error::WaitContextDeleteDescriptor)?;
        self.handlers.lock().remove(&descriptor.as_raw_descriptor());
        Ok(())
    }

    /// Stops this event loop asynchronously. Previous events might not be handled.
    pub fn stop(&self) {
        match self.stop_evt.write(1) {
            Ok(_) => {}
            Err(_) => {
                error!("fail to send event loop stop event, it might already stopped");
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use base::Event;
    use std::sync::{Arc, Condvar, Mutex};

    struct EventLoopTestHandler {
        val: Mutex<u8>,
        cvar: Condvar,
        evt: Event,
    }

    impl EventHandler for EventLoopTestHandler {
        fn on_event(&self) -> std::result::Result<(), ()> {
            self.evt.read().unwrap();
            *self.val.lock().unwrap() += 1;
            self.cvar.notify_one();
            Ok(())
        }
    }

    #[test]
    fn event_loop_test() {
        let (l, j) = EventLoop::start("test".to_string(), None).unwrap();
        let (self_evt, evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
            Ok(v) => v,
            Err(e) => {
                error!("failed creating Event pair: {:?}", e);
                return;
            }
        };
        let h = Arc::new(EventLoopTestHandler {
            val: Mutex::new(0),
            cvar: Condvar::new(),
            evt,
        });
        let t: Arc<dyn EventHandler> = h.clone();
        l.add_event(
            &h.evt,
            WatchingEvents::empty().set_read(),
            Arc::downgrade(&t),
        )
        .unwrap();
        self_evt.write(1).unwrap();
        {
            let mut val = h.val.lock().unwrap();
            while *val < 1 {
                val = h.cvar.wait(val).unwrap();
            }
        }
        l.stop();
        j.join().unwrap();
        assert_eq!(*(h.val.lock().unwrap()), 1);
    }
}
<|endoftext|>