<commit_before>use std::{mem, ptr};
use libc::{c_int, socklen_t};
use fcntl::{Fd, fcntl, F_SETFL, F_SETFD, FD_CLOEXEC, O_NONBLOCK};
use errno::{SysResult, SysError, from_ffi};
use features;

pub use libc::{in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, sa_family_t};

pub use self::consts::*;

mod ffi {
    use libc::{c_int, c_void, socklen_t};
    pub use libc::{socket, listen, bind, accept, connect, setsockopt};

    extern {
        pub fn getsockopt(
            sockfd: c_int,
            level: c_int,
            optname: c_int,
            optval: *mut c_void,
            optlen: *mut socklen_t) -> c_int;
    }
}

// Extra flags - Supported by Linux 2.6.27, normalized on other platforms
bitflags!(
    flags SockFlag: c_int {
        static SOCK_NONBLOCK = 0o0004000,
        static SOCK_CLOEXEC  = 0o2000000
    }
)

pub enum SockAddr {
    SockIpV4(sockaddr_in),
    SockIpV6(sockaddr_in6),
    SockUnix(sockaddr_un)
}

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

    pub type AddressFamily = c_int;

    pub static AF_UNIX: AddressFamily  = 1;
    pub static AF_LOCAL: AddressFamily = AF_UNIX;
    pub static AF_INET: AddressFamily  = 2;
    pub static AF_INET6: AddressFamily = 10;

    pub type SockType = c_int;

    pub static SOCK_STREAM: SockType = 1;
    pub static SOCK_DGRAM: SockType = 2;
    pub static SOCK_SEQPACKET: SockType = 5;
    pub static SOCK_RAW: SockType = 3;
    pub static SOCK_RDM: SockType = 4;

    pub type SockLevel = c_int;

    pub static SOL_IP: SockLevel     = 0;
    pub static SOL_SOCKET: SockLevel = 1;
    pub static SOL_TCP: SockLevel    = 6;
    pub static SOL_UDP: SockLevel    = 17;
    pub static SOL_IPV6: SockLevel   = 41;

    pub type SockOpt = c_int;

    pub static SO_ACCEPTCONN: SockOpt = 30;
    pub static SO_BINDTODEVICE: SockOpt = 25;
    pub static SO_BROADCAST: SockOpt = 6;
    pub static SO_BSDCOMPAT: SockOpt = 14;
    pub static SO_DEBUG: SockOpt = 1;
    pub static SO_DOMAIN: SockOpt = 39;
    pub static SO_ERROR: SockOpt = 4;
    pub static SO_DONTROUTE: SockOpt = 5;
    pub static SO_KEEPALIVE: SockOpt = 9;
    pub static SO_LINGER: SockOpt = 13;
    pub static SO_MARK: SockOpt = 36;
    pub static SO_OOBINLINE: SockOpt = 10;
    pub static SO_PASSCRED: SockOpt = 16;
    pub static SO_PEEK_OFF: SockOpt = 42;
    pub static SO_PEERCRED: SockOpt = 17;
    pub static SO_PRIORITY: SockOpt = 12;
    pub static SO_PROTOCOL: SockOpt = 38;
    pub static SO_RCVBUF: SockOpt = 8;
    pub static SO_RCVBUFFORCE: SockOpt = 33;
    pub static SO_RCVLOWAT: SockOpt = 18;
    pub static SO_SNDLOWAT: SockOpt = 19;
    pub static SO_RCVTIMEO: SockOpt = 20;
    pub static SO_SNDTIMEO: SockOpt = 21;
    pub static SO_REUSEADDR: SockOpt = 2;
    pub static SO_RXQ_OVFL: SockOpt = 40;
    pub static SO_SNDBUF: SockOpt = 7;
    pub static SO_SNDBUFFORCE: SockOpt = 32;
    pub static SO_TIMESTAMP: SockOpt = 29;
    pub static SO_TYPE: SockOpt = 3;
    pub static SO_BUSY_POLL: SockOpt = 46;
}

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

    pub type AddressFamily = c_int;

    pub static AF_UNIX: AddressFamily  = 1;
    pub static AF_LOCAL: AddressFamily = AF_UNIX;
    pub static AF_INET: AddressFamily  = 2;
    pub static AF_INET6: AddressFamily = 30;

    pub type SockType = c_int;

    pub static SOCK_STREAM: SockType = 1;
    pub static SOCK_DGRAM: SockType = 2;
    pub static SOCK_SEQPACKET: SockType = 5;
    pub static SOCK_RAW: SockType = 3;
    pub static SOCK_RDM: SockType = 4;

    pub type SockLevel = c_int;

    pub static SOL_SOCKET: SockLevel = 0xffff;

    pub type SockOpt = c_int;

    pub static SO_ACCEPTCONN: SockOpt          = 0x0002;
    pub static SO_BROADCAST: SockOpt           = 0x0020;
    pub static SO_DEBUG: SockOpt               = 0x0001;
    pub static SO_DONTTRUNC: SockOpt           = 0x2000;
    pub static SO_ERROR: SockOpt               = 0x1007;
    pub static SO_DONTROUTE: SockOpt           = 0x0010;
    pub static SO_KEEPALIVE: SockOpt           = 0x0008;
    pub static SO_LABEL: SockOpt               = 0x1010;
    pub static SO_LINGER: SockOpt              = 0x0080;
    pub static SO_NREAD: SockOpt               = 0x1020;
    pub static SO_NKE: SockOpt                 = 0x1021;
    pub static SO_NOSIGPIPE: SockOpt           = 0x1022;
    pub static SO_NOADDRERR: SockOpt           = 0x1023;
    pub static SO_NOTIFYCONFLICT: SockOpt      = 0x1026;
    pub static SO_NP_EXTENSIONS: SockOpt       = 0x1083;
    pub static SO_NWRITE: SockOpt              = 0x1024;
    pub static SO_OOBINLINE: SockOpt           = 0x0100;
    pub static SO_PEERLABEL: SockOpt           = 0x1011;
    pub static SO_RCVBUF: SockOpt              = 0x1002;
    pub static SO_RCVLOWAT: SockOpt            = 0x1004;
    pub static SO_SNDLOWAT: SockOpt            = 0x1003;
    pub static SO_RCVTIMEO: SockOpt            = 0x1006;
    pub static SO_SNDTIMEO: SockOpt            = 0x1005;
    pub static SO_RANDOMPORT: SockOpt          = 0x1082;
    pub static SO_RESTRICTIONS: SockOpt        = 0x1081;
    pub static SO_RESTRICT_DENYIN: SockOpt     = 0x00000001;
    pub static SO_RESTRICT_DENYOUT: SockOpt    = 0x00000002;
    pub static SO_REUSEADDR: SockOpt           = 0x0004;
    pub static SO_REUSESHAREUID: SockOpt       = 0x1025;
    pub static SO_SNDBUF: SockOpt              = 0x1001;
    pub static SO_TIMESTAMP: SockOpt           = 0x0400;
    pub static SO_TIMESTAMP_MONOTONIC: SockOpt = 0x0800;
    pub static SO_TYPE: SockOpt                = 0x1008;
    pub static SO_WANTMORE: SockOpt            = 0x4000;
    pub static SO_WANTOOBFLAG: SockOpt         = 0x8000;
    #[allow(type_overflow)]
    pub static SO_RESTRICT_DENYSET: SockOpt    = 0x80000000;
}

pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> SysResult<Fd> {
    let feat_atomic = features::socket_atomic_cloexec();

    if feat_atomic {
        ty = ty | flags.bits();
    }

    // TODO: Check the kernel version
    let res = unsafe { ffi::socket(domain, ty, 0) };

    if res < 0 {
        return Err(SysError::last());
    }

    if !feat_atomic {
        if flags.contains(SOCK_CLOEXEC) {
            try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
        }

        if flags.contains(SOCK_NONBLOCK) {
            try!(fcntl(res, F_SETFL(O_NONBLOCK)));
        }
    }

    Ok(res)
}

pub fn listen(sockfd: Fd, backlog: uint) -> SysResult<()> {
    let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
    from_ffi(res)
}

pub fn bind(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

pub fn accept(sockfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    use libc::sockaddr;

    type F = unsafe extern "C" fn(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static accept4: *const ();
    }

    if !accept4.is_null() {
        let res = unsafe {
            mem::transmute::<*const (), F>(accept4)(
                sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits)
        };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(res)
    } else {
        accept4_polyfill(sockfd, flags)
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    accept4_polyfill(sockfd, flags)
}

#[inline]
fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    let res =  unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };

    if res < 0 {
        return Err(SysError::last());
    }

    if flags.contains(SOCK_CLOEXEC) {
        try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(SOCK_NONBLOCK) {
        try!(fcntl(res, F_SETFL(O_NONBLOCK)));
    }

    Ok(res)
}

pub fn connect(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

#[repr(C)]
pub struct linger {
    pub l_onoff: c_int,
    pub l_linger: c_int
}

pub fn getsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &mut T) -> SysResult<uint> {
    let mut len = mem::size_of::<T>() as socklen_t;

    let res = unsafe {
        ffi::getsockopt(
            fd, level, opt,
            mem::transmute(val),
            &mut len as *mut socklen_t)
    };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(len as uint)
}

pub fn setsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &T) -> SysResult<()> {
    let len = mem::size_of::<T>() as socklen_t;

    let res = unsafe {
            ffi::setsockopt(
            fd, level, opt,
            mem::transmute(val),
            len)
    };

    from_ffi(res)
}
<commit_msg>Make macos/ios version of accept4 function public<commit_after>use std::{mem, ptr};
use libc::{c_int, socklen_t};
use fcntl::{Fd, fcntl, F_SETFL, F_SETFD, FD_CLOEXEC, O_NONBLOCK};
use errno::{SysResult, SysError, from_ffi};
use features;

pub use libc::{in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, sa_family_t};

pub use self::consts::*;

mod ffi {
    use libc::{c_int, c_void, socklen_t};
    pub use libc::{socket, listen, bind, accept, connect, setsockopt};

    extern {
        pub fn getsockopt(
            sockfd: c_int,
            level: c_int,
            optname: c_int,
            optval: *mut c_void,
            optlen: *mut socklen_t) -> c_int;
    }
}

// Extra flags - Supported by Linux 2.6.27, normalized on other platforms
bitflags!(
    flags SockFlag: c_int {
        static SOCK_NONBLOCK = 0o0004000,
        static SOCK_CLOEXEC  = 0o2000000
    }
)

pub enum SockAddr {
    SockIpV4(sockaddr_in),
    SockIpV6(sockaddr_in6),
    SockUnix(sockaddr_un)
}

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

    pub type AddressFamily = c_int;

    pub static AF_UNIX: AddressFamily  = 1;
    pub static AF_LOCAL: AddressFamily = AF_UNIX;
    pub static AF_INET: AddressFamily  = 2;
    pub static AF_INET6: AddressFamily = 10;

    pub type SockType = c_int;

    pub static SOCK_STREAM: SockType = 1;
    pub static SOCK_DGRAM: SockType = 2;
    pub static SOCK_SEQPACKET: SockType = 5;
    pub static SOCK_RAW: SockType = 3;
    pub static SOCK_RDM: SockType = 4;

    pub type SockLevel = c_int;

    pub static SOL_IP: SockLevel     = 0;
    pub static SOL_SOCKET: SockLevel = 1;
    pub static SOL_TCP: SockLevel    = 6;
    pub static SOL_UDP: SockLevel    = 17;
    pub static SOL_IPV6: SockLevel   = 41;

    pub type SockOpt = c_int;

    pub static SO_ACCEPTCONN: SockOpt = 30;
    pub static SO_BINDTODEVICE: SockOpt = 25;
    pub static SO_BROADCAST: SockOpt = 6;
    pub static SO_BSDCOMPAT: SockOpt = 14;
    pub static SO_DEBUG: SockOpt = 1;
    pub static SO_DOMAIN: SockOpt = 39;
    pub static SO_ERROR: SockOpt = 4;
    pub static SO_DONTROUTE: SockOpt = 5;
    pub static SO_KEEPALIVE: SockOpt = 9;
    pub static SO_LINGER: SockOpt = 13;
    pub static SO_MARK: SockOpt = 36;
    pub static SO_OOBINLINE: SockOpt = 10;
    pub static SO_PASSCRED: SockOpt = 16;
    pub static SO_PEEK_OFF: SockOpt = 42;
    pub static SO_PEERCRED: SockOpt = 17;
    pub static SO_PRIORITY: SockOpt = 12;
    pub static SO_PROTOCOL: SockOpt = 38;
    pub static SO_RCVBUF: SockOpt = 8;
    pub static SO_RCVBUFFORCE: SockOpt = 33;
    pub static SO_RCVLOWAT: SockOpt = 18;
    pub static SO_SNDLOWAT: SockOpt = 19;
    pub static SO_RCVTIMEO: SockOpt = 20;
    pub static SO_SNDTIMEO: SockOpt = 21;
    pub static SO_REUSEADDR: SockOpt = 2;
    pub static SO_RXQ_OVFL: SockOpt = 40;
    pub static SO_SNDBUF: SockOpt = 7;
    pub static SO_SNDBUFFORCE: SockOpt = 32;
    pub static SO_TIMESTAMP: SockOpt = 29;
    pub static SO_TYPE: SockOpt = 3;
    pub static SO_BUSY_POLL: SockOpt = 46;
}

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

    pub type AddressFamily = c_int;

    pub static AF_UNIX: AddressFamily  = 1;
    pub static AF_LOCAL: AddressFamily = AF_UNIX;
    pub static AF_INET: AddressFamily  = 2;
    pub static AF_INET6: AddressFamily = 30;

    pub type SockType = c_int;

    pub static SOCK_STREAM: SockType = 1;
    pub static SOCK_DGRAM: SockType = 2;
    pub static SOCK_SEQPACKET: SockType = 5;
    pub static SOCK_RAW: SockType = 3;
    pub static SOCK_RDM: SockType = 4;

    pub type SockLevel = c_int;

    pub static SOL_SOCKET: SockLevel = 0xffff;

    pub type SockOpt = c_int;

    pub static SO_ACCEPTCONN: SockOpt          = 0x0002;
    pub static SO_BROADCAST: SockOpt           = 0x0020;
    pub static SO_DEBUG: SockOpt               = 0x0001;
    pub static SO_DONTTRUNC: SockOpt           = 0x2000;
    pub static SO_ERROR: SockOpt               = 0x1007;
    pub static SO_DONTROUTE: SockOpt           = 0x0010;
    pub static SO_KEEPALIVE: SockOpt           = 0x0008;
    pub static SO_LABEL: SockOpt               = 0x1010;
    pub static SO_LINGER: SockOpt              = 0x0080;
    pub static SO_NREAD: SockOpt               = 0x1020;
    pub static SO_NKE: SockOpt                 = 0x1021;
    pub static SO_NOSIGPIPE: SockOpt           = 0x1022;
    pub static SO_NOADDRERR: SockOpt           = 0x1023;
    pub static SO_NOTIFYCONFLICT: SockOpt      = 0x1026;
    pub static SO_NP_EXTENSIONS: SockOpt       = 0x1083;
    pub static SO_NWRITE: SockOpt              = 0x1024;
    pub static SO_OOBINLINE: SockOpt           = 0x0100;
    pub static SO_PEERLABEL: SockOpt           = 0x1011;
    pub static SO_RCVBUF: SockOpt              = 0x1002;
    pub static SO_RCVLOWAT: SockOpt            = 0x1004;
    pub static SO_SNDLOWAT: SockOpt            = 0x1003;
    pub static SO_RCVTIMEO: SockOpt            = 0x1006;
    pub static SO_SNDTIMEO: SockOpt            = 0x1005;
    pub static SO_RANDOMPORT: SockOpt          = 0x1082;
    pub static SO_RESTRICTIONS: SockOpt        = 0x1081;
    pub static SO_RESTRICT_DENYIN: SockOpt     = 0x00000001;
    pub static SO_RESTRICT_DENYOUT: SockOpt    = 0x00000002;
    pub static SO_REUSEADDR: SockOpt           = 0x0004;
    pub static SO_REUSESHAREUID: SockOpt       = 0x1025;
    pub static SO_SNDBUF: SockOpt              = 0x1001;
    pub static SO_TIMESTAMP: SockOpt           = 0x0400;
    pub static SO_TIMESTAMP_MONOTONIC: SockOpt = 0x0800;
    pub static SO_TYPE: SockOpt                = 0x1008;
    pub static SO_WANTMORE: SockOpt            = 0x4000;
    pub static SO_WANTOOBFLAG: SockOpt         = 0x8000;
    #[allow(type_overflow)]
    pub static SO_RESTRICT_DENYSET: SockOpt    = 0x80000000;
}

pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> SysResult<Fd> {
    let feat_atomic = features::socket_atomic_cloexec();

    if feat_atomic {
        ty = ty | flags.bits();
    }

    // TODO: Check the kernel version
    let res = unsafe { ffi::socket(domain, ty, 0) };

    if res < 0 {
        return Err(SysError::last());
    }

    if !feat_atomic {
        if flags.contains(SOCK_CLOEXEC) {
            try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
        }

        if flags.contains(SOCK_NONBLOCK) {
            try!(fcntl(res, F_SETFL(O_NONBLOCK)));
        }
    }

    Ok(res)
}

pub fn listen(sockfd: Fd, backlog: uint) -> SysResult<()> {
    let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
    from_ffi(res)
}

pub fn bind(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

pub fn accept(sockfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    use libc::sockaddr;

    type F = unsafe extern "C" fn(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static accept4: *const ();
    }

    if !accept4.is_null() {
        let res = unsafe {
            mem::transmute::<*const (), F>(accept4)(
                sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits)
        };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(res)
    } else {
        accept4_polyfill(sockfd, flags)
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    accept4_polyfill(sockfd, flags)
}

#[inline]
fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    let res =  unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };

    if res < 0 {
        return Err(SysError::last());
    }

    if flags.contains(SOCK_CLOEXEC) {
        try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(SOCK_NONBLOCK) {
        try!(fcntl(res, F_SETFL(O_NONBLOCK)));
    }

    Ok(res)
}

pub fn connect(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

#[repr(C)]
pub struct linger {
    pub l_onoff: c_int,
    pub l_linger: c_int
}

pub fn getsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &mut T) -> SysResult<uint> {
    let mut len = mem::size_of::<T>() as socklen_t;

    let res = unsafe {
        ffi::getsockopt(
            fd, level, opt,
            mem::transmute(val),
            &mut len as *mut socklen_t)
    };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(len as uint)
}

pub fn setsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &T) -> SysResult<()> {
    let len = mem::size_of::<T>() as socklen_t;

    let res = unsafe {
            ffi::setsockopt(
            fd, level, opt,
            mem::transmute(val),
            len)
    };

    from_ffi(res)
}
<|endoftext|>


<commit_before>use std::io::{self, BufRead, BufReader, BufWriter, Read, Write};
const BLOCK_SIZE: usize = 512;

#[derive(Clone, Copy, Debug)]
#[repr(u8)]
enum SectorState {
    Untried = b'?',
    Untrimmed = b'*',
    Unscraped = b'/',
    Bad = b'-',
    Rescued = b'+',
}

#[derive(Debug)]
pub struct MapFile {
    pos: u64,
    status: u8,
    block_size: usize,
    sector_states: Vec<u8>,
}

impl MapFile {
    pub fn write_to_stream<W: Write>(&self, write: W) -> io::Result<()> {
        let mut write = BufWriter::new(write);
        writeln!(&mut write, "0x{:08X}     {}", self.pos, self.status as char)?;
        let mut current = None;
        let mut size = 0;
        let mut start = 0;

        for (idx, state) in self.sector_states.iter().enumerate() {
            if current == Some(*state) {
                size += self.block_size;
            } else {
                if size > 0 {
                    writeln!(&mut write, "0x{:08X}  0x{:08X}  {}", start, size, current.unwrap() as char)?;
                }
                start = idx * self.block_size;
                size = self.block_size;
                current = Some(*state);
            }
        }
        if size > 0 {
            writeln!(&mut write, "0x{:08X}  0x{:08X}  {}", start, size, current.unwrap() as char)?;
        }
        Ok(())
    }

    pub fn get_size_bytes(&self) -> u64 {
        (self.block_size as u64) * (self.sector_states.len() as u64)
    }

    pub fn read_from_stream<R>(read: R) -> io::Result<MapFile> where R: Read {
        let buf_reader = BufReader::new(read);
        let block_size = BLOCK_SIZE;
        let mut read_state = false;
        let mut pos = None;
        let mut status = None;
        let mut states = Vec::new();

        for line in buf_reader.lines() {
            let line = line?;
            if line.starts_with("#") {
                continue;
            }

            let radix = 16;
            if !read_state {
                let mut iter = line.split_whitespace();
                pos = Some(u64::from_str_radix(&iter.next().unwrap()[2..], radix).unwrap());
                status = Some(iter.next().unwrap().parse::<String>().unwrap().trim().chars().next().unwrap() as u8);
                read_state = true;
            } else {
                let mut iter = line.split_whitespace();
                let pos = u64::from_str_radix(&iter.next().unwrap()[2..], radix).unwrap();
                let size = u64::from_str_radix(&iter.next().unwrap()[2..], radix).unwrap();
                let state = iter.next().unwrap().chars().next().unwrap() as u8;

                states.resize(((size + pos) / (block_size as u64)) as usize, SectorState::Untried as u8);
                assert_eq!((size + pos) % (block_size as u64), 0);
                let start = pos / (block_size as u64);
                assert_eq!(start * (block_size as u64), pos);
                let count = size / (block_size as u64);
                assert_eq!(count * (block_size as u64), size);
                for i in start..(start + count) {
                    states[i as usize] = state;
                }
            }
        }

        let result = MapFile {
            pos: pos.unwrap(),
            status: status.unwrap(),
            block_size: block_size,
            sector_states: states,
        };
        Ok(result)
    }
}

<commit_msg>Use TaggedRange for MapFile.<commit_after>use std::io::{self, BufRead, BufReader, BufWriter, Read, Write};
use tagged_range::{self, TaggedRange};
use std::error::Error;
use std::fmt::{self, Display};
use std::cmp;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum SectorState {
    Untried = b'?',
    Untrimmed = b'*',
    Unscraped = b'/',
    Bad = b'-',
    Rescued = b'+',
}

#[derive(Debug)]
pub struct ParseSectorStateError {
}

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

impl Error for ParseSectorStateError {
    fn description(&self) -> &str {
        "Unknown character when parsing sector state."
    }
}

impl SectorState {
    pub fn from_u8(c: u8) -> Result<SectorState, ParseSectorStateError> {
        use self::SectorState::*;
        for state in [Untried, Untrimmed, Unscraped, Bad, Rescued].iter() {
            if c == *state as u8 {
                return Ok(state.clone())
            }
        }
        Err(ParseSectorStateError{})
    }

    pub fn as_char(&self) -> char {
        *self as u8 as char
    }
}

#[derive(Debug)]
pub struct MapFile {
    pos: u64,
    status: u8,
    size_bytes: u64,
    sector_states: TaggedRange<SectorState>,
}

impl MapFile {
    pub fn write_to_stream<W: Write>(&self, write: W) -> io::Result<()> {
        let mut write = BufWriter::new(write);
        writeln!(&mut write, "0x{:08X}     {}", self.pos, self.status as char)?;
        for region in self.sector_states.into_iter() {
            writeln!(&mut write, "0x{:08X}  0x{:08X}  {}", region.start, region.length, region.tag.as_char())?;
        }
        Ok(())
    }

    pub fn get_size_bytes(&self) -> u64 {
        self.size_bytes
    }

    pub fn read_from_stream<R>(read: R) -> io::Result<MapFile> where R: Read {
        let buf_reader = BufReader::new(read);
        let mut read_state = false;
        let mut pos = None;
        let mut status = None;
        let mut sector_states = TaggedRange::new();
        let mut size_bytes = 0;

        for line in buf_reader.lines() {
            let line = line?;
            if line.starts_with("#") {
                continue;
            }

            let radix = 16;
            if !read_state {
                let mut iter = line.split_whitespace();
                pos = Some(u64::from_str_radix(&iter.next().unwrap()[2..], radix).unwrap());
                status = Some(iter.next().unwrap().parse::<String>().unwrap().trim().chars().next().unwrap() as u8);
                read_state = true;
            } else {
                let mut iter = line.split_whitespace();
                let pos = u64::from_str_radix(&iter.next().unwrap()[2..], radix).unwrap();
                let size = u64::from_str_radix(&iter.next().unwrap()[2..], radix).unwrap();
                let state = SectorState::from_u8(iter.next().unwrap().chars().next().unwrap() as u8).unwrap();
                sector_states.put(pos..(pos+size), state);
                size_bytes = cmp::max(size_bytes, pos + size);
            }
        }

        let result = MapFile {
            pos: pos.unwrap(),
            status: status.unwrap(),
            sector_states: sector_states,
            size_bytes: size_bytes,
        };
        Ok(result)
    }
}

impl<'a> IntoIterator for &'a MapFile {
    type IntoIter = <&'a TaggedRange<SectorState> as IntoIterator>::IntoIter;
    type Item = tagged_range::Region<SectorState>;

    fn into_iter(self) -> Self::IntoIter {
        self.sector_states.into_iter()
    }
}

<|endoftext|>


<commit_before>use std::mem;

use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.parse_u32()?;
        let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
        Ok(SymbolIter::new(symbols.into()))
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => unimplemented!(),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// Index of a file entry in the module.
///
/// Use the [`LineProgram`] to resolve information on the file from this offset.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u16>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u16>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over line records for the given section offset.
    ///
    /// This does not work with any arbitrary section offset. The iterator only returns lines if the
    /// section offset is the start of a line block. This is true for procedure or symbol offsets
    /// that specify line information. For all other offsets, the iterator will be empty.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<commit_msg>Return unimplemented error instead of unwinding<commit_after>use std::mem;

use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.parse_u32()?;
        let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
        Ok(SymbolIter::new(symbols.into()))
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// Index of a file entry in the module.
///
/// Use the [`LineProgram`] to resolve information on the file from this offset.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u16>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u16>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over line records for the given section offset.
    ///
    /// This does not work with any arbitrary section offset. The iterator only returns lines if the
    /// section offset is the start of a line block. This is true for procedure or symbol offsets
    /// that specify line information. For all other offsets, the iterator will be empty.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    ast::Selection,
    value::{Object, ScalarValue, Value},
};

use crate::{
    executor::{ExecutionResult, Executor},
    parser::Spanning,
};

use crate::BoxFuture;

use super::base::{is_excluded, merge_key_into, Arguments, GraphQLType};

/// TODO: docs.
pub trait GraphQLTypeAsync<S>: GraphQLType<S> + Send + Sync
where
    Self::Context: Send + Sync,
    Self::TypeInfo: Send + Sync,
    S: ScalarValue + Send + Sync,
{
    fn resolve_field_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        field_name: &'a str,
        arguments: &'a Arguments<S>,
        executor: &'a Executor<Self::Context, S>,
    ) -> BoxFuture<'a, ExecutionResult<S>> {
        panic!("resolve_field must be implemented by object types");
    }

    fn resolve_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        selection_set: Option<&'a [Selection<S>]>,
        executor: &'a Executor<Self::Context, S>,
    ) -> BoxFuture<'a, ExecutionResult<S>> {
        if let Some(selection_set) = selection_set {
            Box::pin(async move {
                let value =
                    resolve_selection_set_into_async(self, info, selection_set, executor).await;
                Ok(value)
            })
        } else {
            panic!("resolve() must be implemented by non-object output types");
        }
    }

    fn resolve_into_type_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        type_name: &str,
        selection_set: Option<&'a [Selection<'a, S>]>,
        executor: &'a Executor<'a, Self::Context, S>,
    ) -> BoxFuture<'a, ExecutionResult<S>> {
        if Self::name(info).unwrap() == type_name {
            self.resolve_async(info, selection_set, executor)
        } else {
            panic!("resolve_into_type_async must be implemented by unions and interfaces");
        }
    }
}

// Wrapper function around resolve_selection_set_into_async_recursive.
// This wrapper is necessary because async fns can not be recursive.
pub(crate) fn resolve_selection_set_into_async<'a, 'e, T, CtxT, S>(
    instance: &'a T,
    info: &'a T::TypeInfo,
    selection_set: &'e [Selection<'e, S>],
    executor: &'e Executor<'e, CtxT, S>,
) -> BoxFuture<'a, Value<S>>
where
    T: GraphQLTypeAsync<S, Context = CtxT>,
    T::TypeInfo: Send + Sync,
    S: ScalarValue + Send + Sync,
    CtxT: Send + Sync,
    'e: 'a,
{
    Box::pin(resolve_selection_set_into_async_recursive(
        instance,
        info,
        selection_set,
        executor,
    ))
}

struct AsyncField<S> {
    name: String,
    value: Option<Value<S>>,
}

enum AsyncValue<S> {
    Field(AsyncField<S>),
    Nested(Value<S>),
}

pub(crate) async fn resolve_selection_set_into_async_recursive<'a, T, CtxT, S>(
    instance: &'a T,
    info: &'a T::TypeInfo,
    selection_set: &'a [Selection<'a, S>],
    executor: &'a Executor<'a, CtxT, S>,
) -> Value<S>
where
    T: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
    T::TypeInfo: Send + Sync,
    S: ScalarValue + Send + Sync,
    CtxT: Send + Sync,
{
    use futures::stream::{FuturesOrdered, StreamExt};

    let mut object = Object::with_capacity(selection_set.len());

    let mut async_values = FuturesOrdered::<BoxFuture<'a, AsyncValue<S>>>::new();

    let meta_type = executor
        .schema()
        .concrete_type_by_name(
            T::name(info)
                .expect("Resolving named type's selection set")
                .as_ref(),
        )
        .expect("Type not found in schema");

    for selection in selection_set {
        match *selection {
            Selection::Field(Spanning {
                item: ref f,
                start: ref start_pos,
                ..
            }) => {
                if is_excluded(&f.directives, executor.variables()) {
                    continue;
                }

                let response_name = f.alias.as_ref().unwrap_or(&f.name).item;

                if f.name.item == "__typename" {
                    object.add_field(
                        response_name,
                        Value::scalar(instance.concrete_type_name(executor.context(), info)),
                    );
                    continue;
                }

                let meta_field = meta_type.field_by_name(f.name.item).unwrap_or_else(|| {
                    panic!(format!(
                        "Field {} not found on type {:?}",
                        f.name.item,
                        meta_type.name()
                    ))
                });

                let exec_vars = executor.variables();

                let sub_exec = executor.field_sub_executor(
                    &response_name,
                    f.name.item,
                    start_pos.clone(),
                    f.selection_set.as_ref().map(|v| &v[..]),
                );
                let args = Arguments::new(
                    f.arguments.as_ref().map(|m| {
                        m.item
                            .iter()
                            .map(|&(ref k, ref v)| (k.item, v.item.clone().into_const(exec_vars)))
                            .collect()
                    }),
                    &meta_field.arguments,
                );

                let pos = start_pos.clone();
                let is_non_null = meta_field.field_type.is_non_null();

                let response_name = response_name.to_string();
                let field_future = async move {
                    // TODO: implement custom future type instead of
                    //       two-level boxing.
                    let res = instance
                        .resolve_field_async(info, f.name.item, &args, &sub_exec)
                        .await;

                    let value = match res {
                        Ok(Value::Null) if is_non_null => None,
                        Ok(v) => Some(v),
                        Err(e) => {
                            sub_exec.push_error_at(e, pos);

                            if is_non_null {
                                None
                            } else {
                                Some(Value::null())
                            }
                        }
                    };
                    AsyncValue::Field(AsyncField {
                        name: response_name,
                        value,
                    })
                };
                async_values.push(Box::pin(field_future));
            }
            Selection::FragmentSpread(Spanning {
                item: ref spread, ..
            }) => {
                if is_excluded(&spread.directives, executor.variables()) {
                    continue;
                }

                println!("WHATEVR");

                // TODO: prevent duplicate boxing.
                let f = async move {
                    let fragment = &executor
                        .fragment_by_name(spread.name.item)
                        .expect("Fragment could not be found");
                    let value = resolve_selection_set_into_async(
                        instance,
                        info,
                        &fragment.selection_set[..],
                        executor,
                    )
                    .await;
                    AsyncValue::Nested(value)
                };
                async_values.push(Box::pin(f));
            }
            Selection::InlineFragment(Spanning {
                item: ref fragment,
                start: ref start_pos,
                ..
            }) => {
                if is_excluded(&fragment.directives, executor.variables()) {
                    continue;
                }

                let sub_exec = executor.type_sub_executor(
                    fragment.type_condition.as_ref().map(|c| c.item),
                    Some(&fragment.selection_set[..]),
                );

                if let Some(ref type_condition) = fragment.type_condition {
                    let sub_result = instance
                        .resolve_into_type_async(
                            info,
                            type_condition.item,
                            Some(&fragment.selection_set[..]),
                            &sub_exec,
                        )
                        .await;

                    if let Ok(Value::Object(obj)) = sub_result {
                        for (k, v) in obj {
                            // TODO: prevent duplicate boxing.
                            let f = async move {
                                AsyncValue::Field(AsyncField {
                                    name: k,
                                    value: Some(v),
                                })
                            };
                            async_values.push(Box::pin(f));
                        }
                    } else if let Err(e) = sub_result {
                        sub_exec.push_error_at(e, start_pos.clone());
                    }
                } else {
                    let f = async move {
                        let value = resolve_selection_set_into_async(
                            instance,
                            info,
                            &fragment.selection_set[..],
                            &sub_exec,
                        )
                        .await;
                        AsyncValue::Nested(value)
                    };
                    async_values.push(Box::pin(f));
                }
            }
        }
    }

    while let Some(item) = async_values.next().await {
        match item {
            AsyncValue::Field(AsyncField { name, value }) => {
                if let Some(value) = value {
                    merge_key_into(&mut object, &name, value);
                } else {
                    return Value::null();
                }
            }
            AsyncValue::Nested(obj) => match obj {
                v @ Value::Null => {
                    return v;
                }
                Value::Object(obj) => {
                    for (k, v) in obj {
                        merge_key_into(&mut object, &k, v);
                    }
                }
                _ => unreachable!(),
            },
        }
    }

    Value::Object(object)
}
<commit_msg>Add docs to silence warnings for async (#563)<commit_after>use crate::{
    ast::Selection,
    value::{Object, ScalarValue, Value},
};

use crate::{
    executor::{ExecutionResult, Executor},
    parser::Spanning,
};

use crate::BoxFuture;

use super::base::{is_excluded, merge_key_into, Arguments, GraphQLType};

/// TODO: docs.
pub trait GraphQLTypeAsync<S>: GraphQLType<S> + Send + Sync
where
    Self::Context: Send + Sync,
    Self::TypeInfo: Send + Sync,
    S: ScalarValue + Send + Sync,
{
    /// Resolve the value of a single field on this type.
    ///
    /// The arguments object contain all specified arguments, with default
    /// values substituted for the ones not provided by the query.
    ///
    /// The executor can be used to drive selections into sub-objects.
    ///
    /// The default implementation panics.
    fn resolve_field_async<'a>(
        &'a self,
        _info: &'a Self::TypeInfo,
        _field_name: &'a str,
        _arguments: &'a Arguments<S>,
        _executor: &'a Executor<Self::Context, S>,
    ) -> BoxFuture<'a, ExecutionResult<S>> {
        panic!("resolve_field must be implemented by object types");
    }

    /// Resolve the provided selection set against the current object.
    ///
    /// For non-object types, the selection set will be `None` and the value
    /// of the object should simply be returned.
    ///
    /// For objects, all fields in the selection set should be resolved.
    /// The default implementation uses `resolve_field` to resolve all fields,
    /// including those through fragment expansion.
    ///
    /// Since the GraphQL spec specificies that errors during field processing
    /// should result in a null-value, this might return Ok(Null) in case of
    /// failure. Errors are recorded internally.
    fn resolve_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        selection_set: Option<&'a [Selection<S>]>,
        executor: &'a Executor<Self::Context, S>,
    ) -> BoxFuture<'a, ExecutionResult<S>> {
        if let Some(selection_set) = selection_set {
            Box::pin(async move {
                let value =
                    resolve_selection_set_into_async(self, info, selection_set, executor).await;
                Ok(value)
            })
        } else {
            panic!("resolve() must be implemented by non-object output types");
        }
    }

    /// Resolve this interface or union into a concrete type
    ///
    /// Try to resolve the current type into the type name provided. If the
    /// type matches, pass the instance along to `executor.resolve`.
    ///
    /// The default implementation panics.
    fn resolve_into_type_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        type_name: &str,
        selection_set: Option<&'a [Selection<'a, S>]>,
        executor: &'a Executor<'a, Self::Context, S>,
    ) -> BoxFuture<'a, ExecutionResult<S>> {
        if Self::name(info).unwrap() == type_name {
            self.resolve_async(info, selection_set, executor)
        } else {
            panic!("resolve_into_type_async must be implemented by unions and interfaces");
        }
    }
}

// Wrapper function around resolve_selection_set_into_async_recursive.
// This wrapper is necessary because async fns can not be recursive.
pub(crate) fn resolve_selection_set_into_async<'a, 'e, T, CtxT, S>(
    instance: &'a T,
    info: &'a T::TypeInfo,
    selection_set: &'e [Selection<'e, S>],
    executor: &'e Executor<'e, CtxT, S>,
) -> BoxFuture<'a, Value<S>>
where
    T: GraphQLTypeAsync<S, Context = CtxT>,
    T::TypeInfo: Send + Sync,
    S: ScalarValue + Send + Sync,
    CtxT: Send + Sync,
    'e: 'a,
{
    Box::pin(resolve_selection_set_into_async_recursive(
        instance,
        info,
        selection_set,
        executor,
    ))
}

struct AsyncField<S> {
    name: String,
    value: Option<Value<S>>,
}

enum AsyncValue<S> {
    Field(AsyncField<S>),
    Nested(Value<S>),
}

pub(crate) async fn resolve_selection_set_into_async_recursive<'a, T, CtxT, S>(
    instance: &'a T,
    info: &'a T::TypeInfo,
    selection_set: &'a [Selection<'a, S>],
    executor: &'a Executor<'a, CtxT, S>,
) -> Value<S>
where
    T: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
    T::TypeInfo: Send + Sync,
    S: ScalarValue + Send + Sync,
    CtxT: Send + Sync,
{
    use futures::stream::{FuturesOrdered, StreamExt};

    let mut object = Object::with_capacity(selection_set.len());

    let mut async_values = FuturesOrdered::<BoxFuture<'a, AsyncValue<S>>>::new();

    let meta_type = executor
        .schema()
        .concrete_type_by_name(
            T::name(info)
                .expect("Resolving named type's selection set")
                .as_ref(),
        )
        .expect("Type not found in schema");

    for selection in selection_set {
        match *selection {
            Selection::Field(Spanning {
                item: ref f,
                start: ref start_pos,
                ..
            }) => {
                if is_excluded(&f.directives, executor.variables()) {
                    continue;
                }

                let response_name = f.alias.as_ref().unwrap_or(&f.name).item;

                if f.name.item == "__typename" {
                    object.add_field(
                        response_name,
                        Value::scalar(instance.concrete_type_name(executor.context(), info)),
                    );
                    continue;
                }

                let meta_field = meta_type.field_by_name(f.name.item).unwrap_or_else(|| {
                    panic!(format!(
                        "Field {} not found on type {:?}",
                        f.name.item,
                        meta_type.name()
                    ))
                });

                let exec_vars = executor.variables();

                let sub_exec = executor.field_sub_executor(
                    &response_name,
                    f.name.item,
                    start_pos.clone(),
                    f.selection_set.as_ref().map(|v| &v[..]),
                );
                let args = Arguments::new(
                    f.arguments.as_ref().map(|m| {
                        m.item
                            .iter()
                            .map(|&(ref k, ref v)| (k.item, v.item.clone().into_const(exec_vars)))
                            .collect()
                    }),
                    &meta_field.arguments,
                );

                let pos = start_pos.clone();
                let is_non_null = meta_field.field_type.is_non_null();

                let response_name = response_name.to_string();
                let field_future = async move {
                    // TODO: implement custom future type instead of
                    //       two-level boxing.
                    let res = instance
                        .resolve_field_async(info, f.name.item, &args, &sub_exec)
                        .await;

                    let value = match res {
                        Ok(Value::Null) if is_non_null => None,
                        Ok(v) => Some(v),
                        Err(e) => {
                            sub_exec.push_error_at(e, pos);

                            if is_non_null {
                                None
                            } else {
                                Some(Value::null())
                            }
                        }
                    };
                    AsyncValue::Field(AsyncField {
                        name: response_name,
                        value,
                    })
                };
                async_values.push(Box::pin(field_future));
            }
            Selection::FragmentSpread(Spanning {
                item: ref spread, ..
            }) => {
                if is_excluded(&spread.directives, executor.variables()) {
                    continue;
                }

                println!("WHATEVR");

                // TODO: prevent duplicate boxing.
                let f = async move {
                    let fragment = &executor
                        .fragment_by_name(spread.name.item)
                        .expect("Fragment could not be found");
                    let value = resolve_selection_set_into_async(
                        instance,
                        info,
                        &fragment.selection_set[..],
                        executor,
                    )
                    .await;
                    AsyncValue::Nested(value)
                };
                async_values.push(Box::pin(f));
            }
            Selection::InlineFragment(Spanning {
                item: ref fragment,
                start: ref start_pos,
                ..
            }) => {
                if is_excluded(&fragment.directives, executor.variables()) {
                    continue;
                }

                let sub_exec = executor.type_sub_executor(
                    fragment.type_condition.as_ref().map(|c| c.item),
                    Some(&fragment.selection_set[..]),
                );

                if let Some(ref type_condition) = fragment.type_condition {
                    let sub_result = instance
                        .resolve_into_type_async(
                            info,
                            type_condition.item,
                            Some(&fragment.selection_set[..]),
                            &sub_exec,
                        )
                        .await;

                    if let Ok(Value::Object(obj)) = sub_result {
                        for (k, v) in obj {
                            // TODO: prevent duplicate boxing.
                            let f = async move {
                                AsyncValue::Field(AsyncField {
                                    name: k,
                                    value: Some(v),
                                })
                            };
                            async_values.push(Box::pin(f));
                        }
                    } else if let Err(e) = sub_result {
                        sub_exec.push_error_at(e, start_pos.clone());
                    }
                } else {
                    let f = async move {
                        let value = resolve_selection_set_into_async(
                            instance,
                            info,
                            &fragment.selection_set[..],
                            &sub_exec,
                        )
                        .await;
                        AsyncValue::Nested(value)
                    };
                    async_values.push(Box::pin(f));
                }
            }
        }
    }

    while let Some(item) = async_values.next().await {
        match item {
            AsyncValue::Field(AsyncField { name, value }) => {
                if let Some(value) = value {
                    merge_key_into(&mut object, &name, value);
                } else {
                    return Value::null();
                }
            }
            AsyncValue::Nested(obj) => match obj {
                v @ Value::Null => {
                    return v;
                }
                Value::Object(obj) => {
                    for (k, v) in obj {
                        merge_key_into(&mut object, &k, v);
                    }
                }
                _ => unreachable!(),
            },
        }
    }

    Value::Object(object)
}
<|endoftext|>


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

//! Tidy check to ensure that unstable features are all in order
//!
//! This check will ensure properties like:
//!
//! * All stability attributes look reasonably well formed
//! * The set of library features is disjoint from the set of language features
//! * Library features have at most one stability level
//! * Library features have at most one `since` value
//! * All stability attributes have tests to ensure they are actually stable/unstable

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(PartialEq)]
enum Status {
    Stable,
    Unstable,
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let as_str = match *self {
            Status::Stable => "stable",
            Status::Unstable => "unstable",
        };
        fmt::Display::fmt(as_str, f)
    }
}

struct Feature {
    level: Status,
    since: String,
    has_gate_test: bool,
}

pub fn check(path: &Path, bad: &mut bool) {
    let mut features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
    assert!(!features.is_empty());
    let mut lib_features = HashMap::<String, Feature>::new();

    let mut contents = String::new();
    super::walk(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                println!("{}:{}: {}", file.display(), i + 1, msg);
                *bad = true;
            };
            let level = if line.contains("[unstable(") {
                Status::Unstable
            } else if line.contains("[stable(") {
                Status::Stable
            } else {
                continue;
            };
            let feature_name = match find_attr_val(line, "feature") {
                Some(name) => name,
                None => {
                    err("malformed stability attribute");
                    continue;
                }
            };
            let since = match find_attr_val(line, "since") {
                Some(name) => name,
                None if level == Status::Stable => {
                    err("malformed stability attribute");
                    continue;
                }
                None => "None",
            };

            if features.contains_key(feature_name) {
                err("duplicating a lang feature");
            }
            if let Some(ref s) = lib_features.get(feature_name) {
                if s.level != level {
                    err("different stability level than before");
                }
                if s.since != since {
                    err("different `since` than before");
                }
                continue;
            }
            lib_features.insert(feature_name.to_owned(),
                                Feature {
                                    level: level,
                                    since: since.to_owned(),
                                    has_gate_test: false,
                                });
        }
    });

    super::walk(&path.join("test/compile-fail"),
                &mut |path| super::filter_dirs(path),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                println!("{}:{}: {}", file.display(), i + 1, msg);
                *bad = true;
            };

            let gate_test_str = "gate-test-";

            if !line.contains(gate_test_str) {
                continue;
            }

            let feature_name = match line.find(gate_test_str) {
                Some(i) => {
                    &line[i+gate_test_str.len()..line[i+1..].find(' ').unwrap_or(line.len())]
                },
                None => continue,
            };
            let found_feature = features.get_mut(feature_name)
                                        .map(|v| { v.has_gate_test = true; () })
                                        .is_some();

            let found_lib_feature = features.get_mut(feature_name)
                                            .map(|v| { v.has_gate_test = true; () })
                                            .is_some();

            if !(found_feature || found_lib_feature) {
                err(&format!("gate-test test found referencing a nonexistent feature '{}'",
                             feature_name));
            }
        }
    });

    // Only check the number of lang features.
    // Obligatory testing for library features is dumb.
    let gate_untested = features.iter()
                                .filter(|&(_, f)| f.level == Status::Unstable)
                                .filter(|&(_, f)| !f.has_gate_test)
                                .count();

    // FIXME get this number down to zero.
    let gate_untested_expected = 94;

    if gate_untested != gate_untested_expected {
        print!("Expected {} gate untested features, but found {}. ",
                gate_untested_expected, gate_untested);
        if gate_untested < gate_untested_expected {
            println!("Did you forget to reduce the expected number?");
        } else {
            println!("Did you forget to add a gate test for your new feature?");
        }
        *bad = true;
    }

    if *bad {
        return;
    }

    let mut lines = Vec::new();
    for (name, feature) in features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lang",
                           feature.level,
                           feature.since));
    }
    for (name, feature) in lib_features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lib",
                           feature.level,
                           feature.since));
    }

    lines.sort();
    for line in lines {
        println!("* {}", line);
    }
}

fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
    line.find(attr)
        .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
        .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
        .map(|(i, j)| &line[i..j])
}

fn collect_lang_features(path: &Path) -> HashMap<String, Feature> {
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    contents.lines()
        .filter_map(|line| {
            let mut parts = line.trim().split(",");
            let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
                Some("active") => Status::Unstable,
                Some("removed") => Status::Unstable,
                Some("accepted") => Status::Stable,
                _ => return None,
            };
            let name = parts.next().unwrap().trim();
            let since = parts.next().unwrap().trim().trim_matches('"');
            Some((name.to_owned(),
                Feature {
                    level: level,
                    since: since.to_owned(),
                    has_gate_test: false,
                }))
        })
        .collect()
}
<commit_msg>Don't require gate tests for removed features<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure that unstable features are all in order
//!
//! This check will ensure properties like:
//!
//! * All stability attributes look reasonably well formed
//! * The set of library features is disjoint from the set of language features
//! * Library features have at most one stability level
//! * Library features have at most one `since` value
//! * All unstable lang features have tests to ensure they are actually unstable

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(PartialEq)]
enum Status {
    Stable,
    Removed,
    Unstable,
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let as_str = match *self {
            Status::Stable => "stable",
            Status::Unstable => "unstable",
            Status::Removed => "removed",
        };
        fmt::Display::fmt(as_str, f)
    }
}

struct Feature {
    level: Status,
    since: String,
    has_gate_test: bool,
}

pub fn check(path: &Path, bad: &mut bool) {
    let mut features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
    assert!(!features.is_empty());
    let mut lib_features = HashMap::<String, Feature>::new();

    let mut contents = String::new();
    super::walk(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                println!("{}:{}: {}", file.display(), i + 1, msg);
                *bad = true;
            };
            let level = if line.contains("[unstable(") {
                Status::Unstable
            } else if line.contains("[stable(") {
                Status::Stable
            } else {
                continue;
            };
            let feature_name = match find_attr_val(line, "feature") {
                Some(name) => name,
                None => {
                    err("malformed stability attribute");
                    continue;
                }
            };
            let since = match find_attr_val(line, "since") {
                Some(name) => name,
                None if level == Status::Stable => {
                    err("malformed stability attribute");
                    continue;
                }
                None => "None",
            };

            if features.contains_key(feature_name) {
                err("duplicating a lang feature");
            }
            if let Some(ref s) = lib_features.get(feature_name) {
                if s.level != level {
                    err("different stability level than before");
                }
                if s.since != since {
                    err("different `since` than before");
                }
                continue;
            }
            lib_features.insert(feature_name.to_owned(),
                                Feature {
                                    level: level,
                                    since: since.to_owned(),
                                    has_gate_test: false,
                                });
        }
    });

    super::walk(&path.join("test/compile-fail"),
                &mut |path| super::filter_dirs(path),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                println!("{}:{}: {}", file.display(), i + 1, msg);
                *bad = true;
            };

            let gate_test_str = "gate-test-";

            if !line.contains(gate_test_str) {
                continue;
            }

            let feature_name = match line.find(gate_test_str) {
                Some(i) => {
                    &line[i+gate_test_str.len()..line[i+1..].find(' ').unwrap_or(line.len())]
                },
                None => continue,
            };
            let found_feature = features.get_mut(feature_name)
                                        .map(|v| { v.has_gate_test = true; () })
                                        .is_some();

            let found_lib_feature = features.get_mut(feature_name)
                                            .map(|v| { v.has_gate_test = true; () })
                                            .is_some();

            if !(found_feature || found_lib_feature) {
                err(&format!("gate-test test found referencing a nonexistent feature '{}'",
                             feature_name));
            }
        }
    });

    // Only check the number of lang features.
    // Obligatory testing for library features is dumb.
    let gate_untested = features.iter()
                                .filter(|&(_, f)| f.level == Status::Unstable)
                                .filter(|&(_, f)| !f.has_gate_test)
                                .count();

    // FIXME get this number down to zero.
    let gate_untested_expected = 94;

    if gate_untested != gate_untested_expected {
        print!("Expected {} gate untested features, but found {}. ",
                gate_untested_expected, gate_untested);
        if gate_untested < gate_untested_expected {
            println!("Did you forget to reduce the expected number?");
        } else {
            println!("Did you forget to add a gate test for your new feature?");
        }
        *bad = true;
    }

    if *bad {
        return;
    }

    let mut lines = Vec::new();
    for (name, feature) in features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lang",
                           feature.level,
                           feature.since));
    }
    for (name, feature) in lib_features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lib",
                           feature.level,
                           feature.since));
    }

    lines.sort();
    for line in lines {
        println!("* {}", line);
    }
}

fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
    line.find(attr)
        .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
        .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
        .map(|(i, j)| &line[i..j])
}

fn collect_lang_features(path: &Path) -> HashMap<String, Feature> {
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    contents.lines()
        .filter_map(|line| {
            let mut parts = line.trim().split(",");
            let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
                Some("active") => Status::Unstable,
                Some("removed") => Status::Removed,
                Some("accepted") => Status::Stable,
                _ => return None,
            };
            let name = parts.next().unwrap().trim();
            let since = parts.next().unwrap().trim().trim_matches('"');
            Some((name.to_owned(),
                Feature {
                    level: level,
                    since: since.to_owned(),
                    has_gate_test: false,
                }))
        })
        .collect()
}
<|endoftext|>


<commit_before>extern crate simple_soap as soap;

#[test]
pub fn constructor() {
    let reader = {
        soap::reader::Reader::from_file("tests/request.xml")
    };

    assert!(reader.is_ok());
}

#[test]
pub fn read() {
    let reader = {
        soap::reader::Reader::from_file("tests/request.xml")
            .unwrap()
    };
}
<commit_msg>Removing bogus tests<commit_after>extern crate webservices;

<|endoftext|>


<commit_before>use crate::error;
use crate::value;
use avro_rs;
use std;
use std::fmt;
use std::io;

pub struct Source<'a, R>(avro_rs::Reader<'a, R>)
where
    R: io::Read;

pub struct Sink<'a, W>(avro_rs::Writer<'a, W>)
where
    W: io::Write;

#[inline]
pub fn source<'a, R>(r: R) -> error::Result<Source<'a, R>>
where
    R: io::Read,
{
    Ok(Source(avro_rs::Reader::new(r).map_err(|e| {
        error::Error::Avro(error::Avro::downcast(e))
    })?))
}

#[inline]
pub fn sink<W>(schema: &avro_rs::Schema, w: W, codec: avro_rs::Codec) -> error::Result<Sink<W>>
where
    W: io::Write,
{
    Ok(Sink(avro_rs::Writer::with_codec(schema, w, codec)))
}

impl<'a, R> value::Source for Source<'a, R>
where
    R: io::Read,
{
    #[inline]
    fn read(&mut self) -> error::Result<Option<value::Value>> {
        match self.0.next() {
            Some(Ok(v)) => Ok(Some(value_from_avro(v))),
            Some(Err(e)) => Err(error::Error::Avro(error::Avro::downcast(e))),
            None => Ok(None),
        }
    }
}

fn value_from_avro(value: avro_rs::types::Value) -> value::Value {
    use avro_rs::types::Value;
    match value {
        Value::Null => value::Value::Unit,
        Value::Boolean(v) => value::Value::Bool(v),
        Value::Int(v) => value::Value::I32(v),
        Value::Long(v) => value::Value::I64(v),
        Value::Float(v) => value::Value::from_f32(v),
        Value::Double(v) => value::Value::from_f64(v),
        Value::Bytes(v) | Value::Fixed(_, v) => value::Value::Bytes(v),
        Value::String(v) | Value::Enum(_, v) => value::Value::String(v),
        Value::Union(boxed) => value_from_avro(*boxed),
        Value::Array(v) => value::Value::Sequence(v.into_iter().map(value_from_avro).collect()),
        Value::Map(v) => value::Value::Map(
            v.into_iter()
                .map(|(k, v)| (value::Value::String(k), value_from_avro(v)))
                .collect(),
        ),
        Value::Record(v) => value::Value::Map(
            v.into_iter()
                .map(|(k, v)| (value::Value::String(k), value_from_avro(v)))
                .collect(),
        ),
    }
}

impl<'a, W> value::Sink for Sink<'a, W>
where
    W: io::Write,
{
    #[inline]
    fn write(&mut self, value: value::Value) -> error::Result<()> {
        self.0
            .append(value_to_avro(value)?)
            .map_err(|e| error::Error::Avro(error::Avro::downcast(e)))?;
        Ok(())
    }
}

fn value_to_avro(value: value::Value) -> error::Result<avro_rs::types::Value> {
    use avro_rs::types::Value;
    use std::convert::TryFrom;
    match value {
        value::Value::Unit => Ok(Value::Null),
        value::Value::Bool(v) => Ok(Value::Boolean(v)),

        value::Value::I8(v) => Ok(Value::Int(i32::from(v))),
        value::Value::I16(v) => Ok(Value::Int(i32::from(v))),
        value::Value::I32(v) => Ok(Value::Int(v)),
        value::Value::I64(v) => Ok(Value::Long(v)),

        value::Value::U8(v) => Ok(Value::Int(i32::from(v))),
        value::Value::U16(v) => Ok(Value::Int(i32::from(v))),
        value::Value::U32(v) => Ok(Value::Long(i64::from(v))),
        value::Value::U64(v) => {
            if let Ok(v) = i64::try_from(v) {
                Ok(Value::Long(v))
            } else {
                Err(error::Error::Format {
                    msg: format!(
                        "Avro output does not support unsigned 64 bit integer: {}",
                        v
                    ),
                })
            }
        }

        value::Value::F32(ordered_float::OrderedFloat(v)) => Ok(Value::Float(v)),
        value::Value::F64(ordered_float::OrderedFloat(v)) => Ok(Value::Double(v)),

        value::Value::Char(v) => Ok(Value::String(format!("{}", v))),
        value::Value::String(v) => Ok(Value::String(v)),
        value::Value::Bytes(v) => Ok(Value::Bytes(v)),

        value::Value::Sequence(v) => Ok(Value::Array(
            v.into_iter()
                .map(value_to_avro)
                .collect::<error::Result<Vec<_>>>()?,
        )),
        value::Value::Map(v) => Ok(Value::Record(
            v.into_iter()
                .map(|(k, v)| match (value_to_string(k), value_to_avro(v)) {
                    (Ok(k), Ok(v)) => Ok((k, v)),
                    (Ok(_), Err(e)) | (Err(e), Ok(_)) | (Err(_), Err(e)) => Err(e),
                })
                .collect::<error::Result<Vec<_>>>()?,
        )),
    }
}

fn value_to_string(value: value::Value) -> error::Result<String> {
    match value {
        value::Value::Char(v) => Ok(format!("{}", v)),
        value::Value::String(v) => Ok(v),
        x => Err(error::Error::Format {
            msg: format!("Avro can only output string keys, got: {:?}", x),
        }),
    }
}

impl<'a, R> fmt::Debug for Source<'a, R>
where
    R: io::Read,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("AvroSource").finish()
    }
}

impl<'a, W> fmt::Debug for Sink<'a, W>
where
    W: io::Write,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("AvroSink").finish()
    }
}

impl<'a, W> Drop for Sink<'a, W>
where
    W: io::Write,
{
    fn drop(&mut self) {
        match self.0.flush() {
            Ok(_) => (),
            Err(error) => panic!(error),
        }
    }
}
<commit_msg>Use format string in panic!()<commit_after>use crate::error;
use crate::value;
use avro_rs;
use std;
use std::fmt;
use std::io;

pub struct Source<'a, R>(avro_rs::Reader<'a, R>)
where
    R: io::Read;

pub struct Sink<'a, W>(avro_rs::Writer<'a, W>)
where
    W: io::Write;

#[inline]
pub fn source<'a, R>(r: R) -> error::Result<Source<'a, R>>
where
    R: io::Read,
{
    Ok(Source(avro_rs::Reader::new(r).map_err(|e| {
        error::Error::Avro(error::Avro::downcast(e))
    })?))
}

#[inline]
pub fn sink<W>(schema: &avro_rs::Schema, w: W, codec: avro_rs::Codec) -> error::Result<Sink<W>>
where
    W: io::Write,
{
    Ok(Sink(avro_rs::Writer::with_codec(schema, w, codec)))
}

impl<'a, R> value::Source for Source<'a, R>
where
    R: io::Read,
{
    #[inline]
    fn read(&mut self) -> error::Result<Option<value::Value>> {
        match self.0.next() {
            Some(Ok(v)) => Ok(Some(value_from_avro(v))),
            Some(Err(e)) => Err(error::Error::Avro(error::Avro::downcast(e))),
            None => Ok(None),
        }
    }
}

fn value_from_avro(value: avro_rs::types::Value) -> value::Value {
    use avro_rs::types::Value;
    match value {
        Value::Null => value::Value::Unit,
        Value::Boolean(v) => value::Value::Bool(v),
        Value::Int(v) => value::Value::I32(v),
        Value::Long(v) => value::Value::I64(v),
        Value::Float(v) => value::Value::from_f32(v),
        Value::Double(v) => value::Value::from_f64(v),
        Value::Bytes(v) | Value::Fixed(_, v) => value::Value::Bytes(v),
        Value::String(v) | Value::Enum(_, v) => value::Value::String(v),
        Value::Union(boxed) => value_from_avro(*boxed),
        Value::Array(v) => value::Value::Sequence(v.into_iter().map(value_from_avro).collect()),
        Value::Map(v) => value::Value::Map(
            v.into_iter()
                .map(|(k, v)| (value::Value::String(k), value_from_avro(v)))
                .collect(),
        ),
        Value::Record(v) => value::Value::Map(
            v.into_iter()
                .map(|(k, v)| (value::Value::String(k), value_from_avro(v)))
                .collect(),
        ),
    }
}

impl<'a, W> value::Sink for Sink<'a, W>
where
    W: io::Write,
{
    #[inline]
    fn write(&mut self, value: value::Value) -> error::Result<()> {
        self.0
            .append(value_to_avro(value)?)
            .map_err(|e| error::Error::Avro(error::Avro::downcast(e)))?;
        Ok(())
    }
}

fn value_to_avro(value: value::Value) -> error::Result<avro_rs::types::Value> {
    use avro_rs::types::Value;
    use std::convert::TryFrom;
    match value {
        value::Value::Unit => Ok(Value::Null),
        value::Value::Bool(v) => Ok(Value::Boolean(v)),

        value::Value::I8(v) => Ok(Value::Int(i32::from(v))),
        value::Value::I16(v) => Ok(Value::Int(i32::from(v))),
        value::Value::I32(v) => Ok(Value::Int(v)),
        value::Value::I64(v) => Ok(Value::Long(v)),

        value::Value::U8(v) => Ok(Value::Int(i32::from(v))),
        value::Value::U16(v) => Ok(Value::Int(i32::from(v))),
        value::Value::U32(v) => Ok(Value::Long(i64::from(v))),
        value::Value::U64(v) => {
            if let Ok(v) = i64::try_from(v) {
                Ok(Value::Long(v))
            } else {
                Err(error::Error::Format {
                    msg: format!(
                        "Avro output does not support unsigned 64 bit integer: {}",
                        v
                    ),
                })
            }
        }

        value::Value::F32(ordered_float::OrderedFloat(v)) => Ok(Value::Float(v)),
        value::Value::F64(ordered_float::OrderedFloat(v)) => Ok(Value::Double(v)),

        value::Value::Char(v) => Ok(Value::String(format!("{}", v))),
        value::Value::String(v) => Ok(Value::String(v)),
        value::Value::Bytes(v) => Ok(Value::Bytes(v)),

        value::Value::Sequence(v) => Ok(Value::Array(
            v.into_iter()
                .map(value_to_avro)
                .collect::<error::Result<Vec<_>>>()?,
        )),
        value::Value::Map(v) => Ok(Value::Record(
            v.into_iter()
                .map(|(k, v)| match (value_to_string(k), value_to_avro(v)) {
                    (Ok(k), Ok(v)) => Ok((k, v)),
                    (Ok(_), Err(e)) | (Err(e), Ok(_)) | (Err(_), Err(e)) => Err(e),
                })
                .collect::<error::Result<Vec<_>>>()?,
        )),
    }
}

fn value_to_string(value: value::Value) -> error::Result<String> {
    match value {
        value::Value::Char(v) => Ok(format!("{}", v)),
        value::Value::String(v) => Ok(v),
        x => Err(error::Error::Format {
            msg: format!("Avro can only output string keys, got: {:?}", x),
        }),
    }
}

impl<'a, R> fmt::Debug for Source<'a, R>
where
    R: io::Read,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("AvroSource").finish()
    }
}

impl<'a, W> fmt::Debug for Sink<'a, W>
where
    W: io::Write,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("AvroSink").finish()
    }
}

impl<'a, W> Drop for Sink<'a, W>
where
    W: io::Write,
{
    fn drop(&mut self) {
        match self.0.flush() {
            Ok(_) => (),
            Err(error) => panic!("{}", error),
        }
    }
}
<|endoftext|>


<commit_before>use core::ptr::Unique;
use core::fmt::Write;
use spin::Mutex;

macro_rules! print {
    ($($arg:tt)*) => ({
        use core::fmt::Write;
        $crate::vga_buffer::WRITER.lock().write_fmt(format_args!($($arg)*)).unwrap();
    });
}

macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;

pub fn clear_screen() {
    for _ in 0..BUFFER_HEIGHT {
        println!("");
    }
}

#[repr(u8)]
pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 3,
    Cyan        = 4,
    Red         = 5,
    Magenta     = 6,
    Brown       = 7,
    LightGray   = 8,
    DarkGrag    = 9,
    LightBlue   = 10,
    LightGreen  = 11,
    LightCyan   = 12,
    LightRed    = 13,
    LightMagenta = 14,
    Yellow      = 15,
    White       = 16,
}

#[derive(Copy, Clone)]
struct ColorCode(u8);

impl ColorCode {
    const fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

struct Buffer {
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: Unique<Buffer>,
}

impl Writer {
    fn new(foreground: Color, background: Color) -> Writer {
        Writer {
            column_position: 0,
            color_code: ColorCode::new(foreground, background),
            buffer: unsafe { Unique::new(0xb8000 as *mut _) },
        }
    }

    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => {
                self.new_line();
            },
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }

                let row = BUFFER_HEIGHT -1;
                let col = self.column_position;

                self.buffer().chars[row][col] = ScreenChar {
                    ascii_character: byte,
                    color_code: ColorCode::new(Color::LightGreen, Color::Black),
                };
                self.column_position += 1;
            }
        }
    }

    pub fn write_str(&mut self, s: &str) {
        for byte in s.bytes() {
            self.write_byte(byte)
        }
    }

    fn buffer(&mut self) -> &mut Buffer {
        unsafe { self.buffer.get_mut() }
    }

    fn new_line(&mut self) {
        for row in 0..(BUFFER_HEIGHT-1) {
            let buffer = self.buffer();
            buffer.chars[row] = buffer.chars[row + 1]
        }
        self.clear_row(BUFFER_HEIGHT-1);
        self.column_position = 0;
    }

    fn clear_row(&mut self, row: usize) {
        let blank = ScreenChar {
            ascii_character: b' ',
            color_code: self.color_code,
        };
        self.buffer().chars[row] = [blank; BUFFER_WIDTH];
    }
}

impl ::core::fmt::Write for Writer {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        for byte in s.bytes() {
            self.write_byte(byte)
        }
        Ok(())
    }
}

pub static WRITER: Mutex<Writer> = Mutex::new(Writer {
    column_position: 0,
    color_code: ColorCode::new(Color::LightGreen, Color::Black),
    buffer: unsafe { Unique::new(0xb8000 as *mut _) },
});

<commit_msg>lib: fixed colour coding<commit_after>use core::ptr::Unique;
use core::fmt::Write;
use spin::Mutex;

macro_rules! print {
    ($($arg:tt)*) => ({
        use core::fmt::Write;
        $crate::vga_buffer::WRITER.lock().write_fmt(format_args!($($arg)*)).unwrap();
    });
}

macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;

pub fn clear_screen() {
    for _ in 0..BUFFER_HEIGHT {
        println!("");
    }
}

#[repr(u8)]
pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Magenta     = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightMagenta = 13,
    Yellow      = 14,
    White       = 15,
}

#[derive(Copy, Clone)]
struct ColorCode(u8);

impl ColorCode {
    const fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

struct Buffer {
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: Unique<Buffer>,
}

impl Writer {
    fn new(foreground: Color, background: Color) -> Writer {
        Writer {
            column_position: 0,
            color_code: ColorCode::new(foreground, background),
            buffer: unsafe { Unique::new(0xb8000 as *mut _) },
        }
    }

    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => {
                self.new_line();
            },
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }

                let row = BUFFER_HEIGHT -1;
                let col = self.column_position;

                self.buffer().chars[row][col] = ScreenChar {
                    ascii_character: byte,
                    color_code: self.color_code,
                };
                self.column_position += 1;
            }
        }
    }

    pub fn write_str(&mut self, s: &str) {
        for byte in s.bytes() {
            self.write_byte(byte)
        }
    }

    fn buffer(&mut self) -> &mut Buffer {
        unsafe { self.buffer.get_mut() }
    }

    fn new_line(&mut self) {
        for row in 0..(BUFFER_HEIGHT-1) {
            let buffer = self.buffer();
            buffer.chars[row] = buffer.chars[row + 1]
        }
        self.clear_row(BUFFER_HEIGHT-1);
        self.column_position = 0;
    }

    fn clear_row(&mut self, row: usize) {
        let blank = ScreenChar {
            ascii_character: b' ',
            color_code: self.color_code,
        };
        self.buffer().chars[row] = [blank; BUFFER_WIDTH];
    }
}

impl ::core::fmt::Write for Writer {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        for byte in s.bytes() {
            self.write_byte(byte)
        }
        Ok(())
    }
}

pub static WRITER: Mutex<Writer> = Mutex::new(Writer {
    column_position: 0,
    color_code: ColorCode::new(Color::LightGreen, Color::Black),
    buffer: unsafe { Unique::new(0xb8000 as *mut _) },
});

<|endoftext|>