use {Error, Result};
#[cfg(not(target_os = "android"))]
use NixPath;
use errno::Errno;
#[cfg(not(target_os = "android"))]
use fcntl::OFlag;
use libc::{self, c_int, c_void, size_t, off_t};
#[cfg(not(target_os = "android"))]
use sys::stat::Mode;
use std::os::unix::io::RawFd;
libc_bitflags!{
    
    pub struct ProtFlags: c_int {
        
        PROT_NONE;
        
        PROT_READ;
        
        PROT_WRITE;
        
        PROT_EXEC;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        PROT_GROWSDOWN;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        PROT_GROWSUP;
    }
}
libc_bitflags!{
    
    pub struct MapFlags: c_int {
        
        MAP_FILE;
        
        MAP_SHARED;
        
        MAP_PRIVATE;
        
        MAP_FIXED;
        
        MAP_ANON;
        
        #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
        MAP_ANONYMOUS;
        
        #[cfg(any(all(any(target_os = "android", target_os = "linux"),
                      any(target_arch = "x86", target_arch = "x86_64")),
                  all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
                  all(target_os = "freebsd", target_pointer_width = "64")))]
        MAP_32BIT;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_GROWSDOWN;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_DENYWRITE;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_EXECUTABLE;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_LOCKED;
        
        
        
        #[cfg(not(target_os = "freebsd"))]
        MAP_NORESERVE;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_POPULATE;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_NONBLOCK;
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MAP_HUGETLB;
        
        #[cfg(target_os = "netbsd")]
        MAP_WIRED;
        
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
        MAP_NOSYNC;
        
        
        
        #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))]
        MAP_RENAME;
        
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
        MAP_HASSEMAPHORE;
        
        #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
        MAP_STACK;
        
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MAP_NOCACHE;
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MAP_JIT;
    }
}
libc_enum!{
    
    
    
    #[repr(i32)]
    pub enum MmapAdvise {
        
        MADV_NORMAL,
        
        MADV_RANDOM,
        
        MADV_SEQUENTIAL,
        
        MADV_WILLNEED,
        
        MADV_DONTNEED,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_REMOVE,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_DONTFORK,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_DOFORK,
        
        
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_HWPOISON,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_MERGEABLE,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_UNMERGEABLE,
        
        #[cfg(any(target_os = "android",
            all(target_os = "linux", any(
                target_arch = "aarch64",
                target_arch = "arm",
                target_arch = "ppc",
                target_arch = "s390x",
                target_arch = "x86",
                target_arch = "x86_64",
                target_arch = "sparc64"))))]
        MADV_SOFT_OFFLINE,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_HUGEPAGE,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_NOHUGEPAGE,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_DONTDUMP,
        
        #[cfg(any(target_os = "android", target_os = "linux"))]
        MADV_DODUMP,
        
        MADV_FREE,
        
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
        MADV_NOSYNC,
        
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
        MADV_AUTOSYNC,
        
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
        MADV_NOCORE,
        
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
        MADV_CORE,
        #[cfg(any(target_os = "freebsd"))]
        MADV_PROTECT,
        
        #[cfg(target_os = "dragonfly")]
        MADV_INVAL,
        
        #[cfg(target_os = "dragonfly")]
        MADV_SETMAP,
        
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MADV_ZERO_WIRED_PAGES,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MADV_FREE_REUSABLE,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MADV_FREE_REUSE,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MADV_CAN_REUSE,
    }
}
libc_bitflags!{
    
    pub struct MsFlags: c_int {
        
        MS_ASYNC;
        
        MS_INVALIDATE;
        
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MS_KILLPAGES;
        
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        MS_DEACTIVATE;
        
        MS_SYNC;
    }
}
libc_bitflags!{
    
    pub struct MlockAllFlags: c_int {
        
        MCL_CURRENT;
        
        MCL_FUTURE;
    }
}
pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(libc::mlock(addr, length)).map(drop)
}
pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(libc::munlock(addr, length)).map(drop)
}
pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
    unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
}
pub fn munlockall() -> Result<()> {
    unsafe { Errno::result(libc::munlockall()) }.map(drop)
}
pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
    if ret == libc::MAP_FAILED {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}
pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(libc::munmap(addr, len)).map(drop)
}
pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
}
pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
}
#[cfg(not(target_os = "android"))]
pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = name.with_nix_path(|cstr| {
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        unsafe {
            libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
        }
        #[cfg(not(any(target_os = "macos", target_os = "ios")))]
        unsafe {
            libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
        }
    })?;
    Errno::result(ret)
}
#[cfg(not(target_os = "android"))]
pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = name.with_nix_path(|cstr| {
        unsafe { libc::shm_unlink(cstr.as_ptr()) }
    })?;
    Errno::result(ret).map(drop)
}