<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(target_os = "linux")]
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 ();
    }

    let feat_atomic = !accept4.is_null();

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

    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)
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn accept4(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>Don't special case accept4<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)
}

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 ();
    }

    let feat_atomic = !accept4.is_null();

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

    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 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>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.is_empty() {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or_else(|| buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! count_ident{
    () => {0};
    ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
}

macro_rules! impl_tuple_collect {
    ($($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => (
        impl<A> TupleCollect for ($($X),*,) {
            type Item = A;
            type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();

                Some(($(
                    { let $Y = iter.next()?; $Y },
                )*))
            }

            fn num_items() -> usize {
                count_ident!($($Y,)*)
            }

            fn left_shift_push(&mut self, item: A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                $(
                    let item = replace($Y_rev, item);
                )*
                drop(item);
            }
        }
    )
}

// This snippet generates the twelve `impl_tuple_collect!` invocations:
//    use core::iter;
//    use itertools::Itertools;
//
//    for i in 1..=12 {
//        println!("impl_tuple_collect!({ty}; {idents}; {rev_idents});",
//            ty=iter::repeat("A").take(i).join(", "),
//            idents=('a'..='z').take(i).join(", "),
//            rev_idents=('a'..='z').take(i).collect_vec().into_iter().rev().join(", ")
//        );
//    }
// It could probably be replaced by a bit more macro cleverness.
impl_tuple_collect!(A; a; a);
impl_tuple_collect!(A, A; a, b; b, a);
impl_tuple_collect!(A, A, A; a, b, c; c, b, a);
impl_tuple_collect!(A, A, A, A; a, b, c, d; d, c, b, a);
impl_tuple_collect!(A, A, A, A, A; a, b, c, d, e; e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A; a, b, c, d, e, f; f, e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A, A; a, b, c, d, e, f, g; g, f, e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h; h, g, f, e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i; i, h, g, f, e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i, j; j, i, h, g, f, e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i, j, k; k, j, i, h, g, f, e, d, c, b, a);
impl_tuple_collect!(A, A, A, A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i, j, k, l; l, k, j, i, h, g, f, e, d, c, b, a);
<commit_msg>More macro cleverness (3) avoid inferrable arguments<commit_after>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.is_empty() {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or_else(|| buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! count_ident{
    () => {0};
    ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
}
macro_rules! ignore_ident{
    ($id:ident, $($t:tt)*) => {$($t)*};
}

macro_rules! impl_tuple_collect {
    ($($Y:ident),* ; $($Y_rev:ident),*) => (
        impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
            type Item = A;
            type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();

                Some(($(
                    { let $Y = iter.next()?; $Y },
                )*))
            }

            fn num_items() -> usize {
                count_ident!($($Y,)*)
            }

            fn left_shift_push(&mut self, item: A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                $(
                    let item = replace($Y_rev, item);
                )*
                drop(item);
            }
        }
    )
}

// This snippet generates the twelve `impl_tuple_collect!` invocations:
//    use core::iter;
//    use itertools::Itertools;
//
//    for i in 1..=12 {
//        println!("impl_tuple_collect!({idents}; {rev_idents});",
//            idents=('a'..='z').take(i).join(", "),
//            rev_idents=('a'..='z').take(i).collect_vec().into_iter().rev().join(", ")
//        );
//    }
// It could probably be replaced by a bit more macro cleverness.
impl_tuple_collect!(a; a);
impl_tuple_collect!(a, b; b, a);
impl_tuple_collect!(a, b, c; c, b, a);
impl_tuple_collect!(a, b, c, d; d, c, b, a);
impl_tuple_collect!(a, b, c, d, e; e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f; f, e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f, g; g, f, e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f, g, h; h, g, f, e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i; i, h, g, f, e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i, j; j, i, h, g, f, e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i, j, k; k, j, i, h, g, f, e, d, c, b, a);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i, j, k, l; l, k, j, i, h, g, f, e, d, c, b, a);
<|endoftext|>


<commit_before>

use std::collections::HashMap;
use std::vec::Vec;
//use  std::error::Error;

pub struct UrlResource<'a> {
    location: Vec<&'a str>,
    params: HashMap<String, String>
}

//#[deriving(Debug)]
pub enum ParseError {
    InvalidUrl,
    InvalidQuery
}
/*
impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RequestParseError::ReadError(ref err) => err.fmt(f),
            RequestParseError::UrlParseError(ref err) => err.fmt(f),
            RequestParseError::JsonParseError(ref err) => err.fmt(f)
        }
    }
}
impl Error for RequestParseError {
    fn description(&self) -> &str {
        match *self {
            RequestParseError::ReadError(ref err) => err.description(),
            RequestParseError::JsonParseError(ref err) => err.description(),
            RequestParseError::UrlParseError(ref err) => err.description()
        }
    }
}
*/

impl<'a> UrlResource<'a> {
    fn new(location: Vec<&'a str>, params: HashMap<String, String>) -> UrlResource<'a> {
        UrlResource { location: location, params: params }
    }
    fn from_resource(location: &'a str) -> UrlResource<'a> {
        UrlResource::new(location.split("/").collect::<Vec<&str>>(),  HashMap::new())
    }
    fn from_resource_and_query(location: &'a str, query: &str) -> UrlResource<'a> {
        UrlResource::new(location.split("/").collect::<Vec<&str>>(), parse_query(query))
    }
}

pub fn parse_url_resource(url: &str) -> Result<UrlResource, ParseError> {

    let url_split = url.split("?").collect::<Vec<&str>>();

    match url_split.len() {
        0 => Err(ParseError::InvalidUrl),
        1 => Ok(UrlResource::from_resource(url_split[0])), //(resource.split("/"), HashMap.new())),
        2 => Ok(UrlResource::from_resource_and_query(url_split[0], url_split[1])),
        _ => Err(ParseError::InvalidUrl),
    }
    /*
    match resource.split("?").collect().as_slice() {
        [resource] => Ok(UrlResource::new(resource.split("/"), HashMap.new())),
        [resource, params] => Ok(UrlResource::new(resource.split("/"), parse_params(params))),
        _ => Err("Foobar")

    }
*/
}

pub fn parse_query(query: &str) -> HashMap<String, String> {
    HashMap::new()
}
<commit_msg>Add unit tests for url parser<commit_after>
use std::collections::HashMap;
use std::vec::Vec;

pub struct UrlResource<'a> {
    location: Vec<&'a str>,
    params: HashMap<String, String>
}

pub enum ParseError {
    InvalidUrl,
    InvalidQuery
}

impl<'a> UrlResource<'a> {
    fn new(location: Vec<&'a str>, params: HashMap<String, String>) -> UrlResource<'a> {
        UrlResource { location: location, params: params }
    }

    fn parse_location(location: &'a str) -> Result<Vec<&'a str>, ParseError> {
        if (location.len() == 0) {
            Err(ParseError::InvalidUrl)
            //        } else if (location.char_at(0) != '/') {
        } else if (location.chars().nth(0).unwrap() != '/') {
            Err(ParseError::InvalidUrl)
        } else {
            Ok(location[1..].split("/").collect())
        }
    }

    fn parse_query(query: &str) -> Result<HashMap<String, String>, ParseError> {
        Ok(HashMap::new())
    }

    fn from_resource(location: &'a str) -> Result<UrlResource<'a>, ParseError> {
        match UrlResource::parse_location(location) {
            Ok(loc_vec) => Ok(UrlResource::new(loc_vec, HashMap::new())),
            Err(e) => Err(e)
        }
    }

    fn from_resource_and_query(location: &'a str, query: &str) -> Result<UrlResource<'a>, ParseError> {
        match UrlResource::parse_location(location) {
            Ok(loc_vec) => {
                match UrlResource::parse_query(query) {
                    Ok(query_map) => Ok(UrlResource::new(loc_vec, query_map)),
                    Err(e) => Err(e),
                }
            },
            Err(e) => Err(e),
        }
    }
}

pub fn parse_url_resource(url: &str) -> Result<UrlResource, ParseError> {

    let url_split = url.split("?").collect::<Vec<&str>>();

    match url_split.len() {
        0 => Err(ParseError::InvalidUrl),
        1 => UrlResource::from_resource(url_split[0]),
        2 => UrlResource::from_resource_and_query(url_split[0], url_split[1]),
        _ => Err(ParseError::InvalidUrl),
    }
}

#[test]
fn it_works() {
    match parse_url_resource("/foo/bar") {
        Ok(rs) => {
            println!("location: {:?} params: {:?}", rs.location, rs.params);
            assert!(rs.location == vec!("foo", "bar"));
        },
        Err(_) => assert!(false),
    }
}

#[test]
fn it_works_2() {
    match parse_url_resource("/foo/bar?a=A&b=B") {
        Ok(rs) => {
            println!("location: {:?} params: {:?}", rs.location, rs.params);
            assert!(rs.location == vec!("foo", "bar"));
            assert!(rs.params == HashMap::new());
        },
        Err(_) => assert!(false),
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

// The classification code for the x86_64 ABI is taken from the clay language
// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp

use lib::llvm::{llvm, Integer, Pointer, Float, Double};
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute, ByValAttribute};
use middle::trans::cabi::*;

use middle::trans::type_::Type;

use core::option;
use core::option::Option;
use core::uint;
use core::vec;

#[deriving(Eq)]
enum RegClass {
    NoClass,
    Int,
    SSEFs,
    SSEFv,
    SSEDs,
    SSEDv,
    SSEInt,
    SSEUp,
    X87,
    X87Up,
    ComplexX87,
    Memory
}

impl Type {
    fn is_reg_ty(&self) -> bool {
        match self.kind() {
            Integer | Pointer | Float | Double => true,
            _ => false
        }
    }
}

impl RegClass {
    fn is_sse(&self) -> bool {
        match *self {
            SSEFs | SSEFv | SSEDs | SSEDv => true,
            _ => false
        }
    }
}

trait ClassList {
    fn is_pass_byval(&self) -> bool;
    fn is_ret_bysret(&self) -> bool;
}

impl<'self> ClassList for &'self [RegClass] {
    fn is_pass_byval(&self) -> bool {
        if self.len() == 0 { return false; }

        let class = self[0];
           class == Memory
        || class == X87
        || class == ComplexX87
    }

    fn is_ret_bysret(&self) -> bool {
        if self.len() == 0 { return false; }

        self[0] == Memory
    }
}

fn classify_ty(ty: Type) -> ~[RegClass] {
    fn align(off: uint, ty: Type) -> uint {
        let a = ty_align(ty);
        return (off + a - 1u) / a * a;
    }

    fn ty_align(ty: Type) -> uint {
        match ty.kind() {
            Integer => {
                unsafe {
                    ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
                }
            }
            Pointer => 8,
            Float => 4,
            Double => 8,
            Struct => {
              if ty.is_packed() {
                1
              } else {
                let str_tys = ty.field_types();
                str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t)))
              }
            }
            Array => {
                let elt = ty.element_type();
                ty_align(elt)
            }
            _ => fail!("ty_size: unhandled type")
        }
    }

    fn ty_size(ty: Type) -> uint {
        match ty.kind() {
            Integer => {
                unsafe {
                    ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
                }
            }
            Pointer => 8,
            Float => 4,
            Double => 8,
            Struct => {
                if ty.is_packed() {
                    let str_tys = ty.field_types();
                    str_tys.iter().fold(0, |s, t| s + ty_size(*t))
                } else {
                    let str_tys = ty.field_types();
                    let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
                    align(size, ty)
                }
            }
            Array => {
                let len = ty.array_length();
                let elt = ty.element_type();
                let eltsz = ty_size(elt);
                len * eltsz
            }
            _ => fail!("ty_size: unhandled type")
        }
    }

    fn all_mem(cls: &mut [RegClass]) {
        for uint::range(0, cls.len()) |i| {
            cls[i] = Memory;
        }
    }

    fn unify(cls: &mut [RegClass],
             i: uint,
             newv: RegClass) {
        if cls[i] == newv {
            return;
        } else if cls[i] == NoClass {
            cls[i] = newv;
        } else if newv == NoClass {
            return;
        } else if cls[i] == Memory || newv == Memory {
            cls[i] = Memory;
        } else if cls[i] == Int || newv == Int {
            cls[i] = Int;
        } else if cls[i] == X87 ||
                  cls[i] == X87Up ||
                  cls[i] == ComplexX87 ||
                  newv == X87 ||
                  newv == X87Up ||
                  newv == ComplexX87 {
            cls[i] = Memory;
        } else {
            cls[i] = newv;
        }
    }

    fn classify_struct(tys: &[Type],
                       cls: &mut [RegClass], i: uint,
                       off: uint) {
        let mut field_off = off;
        for tys.iter().advance |ty| {
            field_off = align(field_off, *ty);
            classify(*ty, cls, i, field_off);
            field_off += ty_size(*ty);
        }
    }

    fn classify(ty: Type,
                cls: &mut [RegClass], ix: uint,
                off: uint) {
        let t_align = ty_align(ty);
        let t_size = ty_size(ty);

        let misalign = off % t_align;
        if misalign != 0u {
            let mut i = off / 8u;
            let e = (off + t_size + 7u) / 8u;
            while i < e {
                unify(cls, ix + i, Memory);
                i += 1u;
            }
            return;
        }

        match ty.kind() {
            Integer |
            Pointer => {
                unify(cls, ix + off / 8u, Int);
            }
            Float => {
                if off % 8u == 4u {
                    unify(cls, ix + off / 8u, SSEFv);
                } else {
                    unify(cls, ix + off / 8u, SSEFs);
                }
            }
            Double => {
                unify(cls, ix + off / 8u, SSEDs);
            }
            Struct => {
                classify_struct(ty.field_types(), cls, ix, off);
            }
            Array => {
                let len = ty.array_length();
                let elt = ty.element_type();
                let eltsz = ty_size(elt);
                let mut i = 0u;
                while i < len {
                    classify(elt, cls, ix, off + i * eltsz);
                    i += 1u;
                }
            }
            _ => fail!("classify: unhandled type")
        }
    }

    fn fixup(ty: Type, cls: &mut [RegClass]) {
        let mut i = 0u;
        let ty_kind = ty.kind();
        let e = cls.len();
        if cls.len() > 2u &&
           (ty_kind == Struct ||
            ty_kind == Array) {
            if cls[i].is_sse() {
                i += 1u;
                while i < e {
                    if cls[i] != SSEUp {
                        all_mem(cls);
                        return;
                    }
                    i += 1u;
                }
            } else {
                all_mem(cls);
                return
            }
        } else {
            while i < e {
                if cls[i] == Memory {
                    all_mem(cls);
                    return;
                }
                if cls[i] == X87Up {
                    // for darwin
                    // cls[i] = SSEDs;
                    all_mem(cls);
                    return;
                }
                if cls[i] == SSEUp {
                    cls[i] = SSEInt;
                } else if cls[i].is_sse() {
                    i += 1;
                    while i != e && cls[i] == SSEUp { i += 1u; }
                } else if cls[i] == X87 {
                    i += 1;
                    while i != e && cls[i] == X87Up { i += 1u; }
                } else {
                    i += 1;
                }
            }
        }
    }

    let words = (ty_size(ty) + 7) / 8;
    let mut cls = vec::from_elem(words, NoClass);
    if words > 4 {
        all_mem(cls);
        let cls = cls;
        return cls;
    }
    classify(ty, cls, 0, 0);
    fixup(ty, cls);
    return cls;
}

fn llreg_ty(cls: &[RegClass]) -> Type {
    fn llvec_len(cls: &[RegClass]) -> uint {
        let mut len = 1u;
        for cls.iter().advance |c| {
            if *c != SSEUp {
                break;
            }
            len += 1u;
        }
        return len;
    }

    let mut tys = ~[];
    let mut i = 0u;
    let e = cls.len();
    while i < e {
        match cls[i] {
            Int => {
                tys.push(Type::i64());
            }
            SSEFv => {
                let vec_len = llvec_len(cls.tailn(i + 1u)) * 2u;
                let vec_ty = Type::vector(&Type::f32(), vec_len as u64);
                tys.push(vec_ty);
                i += vec_len;
                loop;
            }
            SSEFs => {
                tys.push(Type::f32());
            }
            SSEDs => {
                tys.push(Type::f64());
            }
            _ => fail!("llregtype: unhandled class")
        }
        i += 1u;
    }
    return Type::struct_(tys, false);
}

fn x86_64_tys(atys: &[Type],
              rty: Type,
              ret_def: bool) -> FnType {

    fn x86_64_ty(ty: Type,
                 is_mem_cls: &fn(cls: &[RegClass]) -> bool,
                 attr: Attribute) -> (LLVMType, Option<Attribute>) {

        let (cast, attr, ty) = if !ty.is_reg_ty() {
            let cls = classify_ty(ty);
            if is_mem_cls(cls) {
                (false, option::Some(attr), ty.ptr_to())
            } else {
                (true, option::None, llreg_ty(cls))
            }
        } else {
            (false, option::None, ty)
        };

        (LLVMType { cast: cast, ty: ty }, attr)
    }

    let mut arg_tys = ~[];
    let mut attrs = ~[];
    for atys.iter().advance |t| {
        let (ty, attr) = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute);
        arg_tys.push(ty);
        attrs.push(attr);
    }
    let mut (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(),
                                       StructRetAttribute);
    let sret = ret_attr.is_some();
    if sret {
        arg_tys = vec::append(~[ret_ty], arg_tys);
        ret_ty = LLVMType {
                   cast:  false,
                   ty: Type::void()
                 };
        attrs = vec::append(~[ret_attr], attrs);
    } else if !ret_def {
        ret_ty = LLVMType {
                   cast: false,
                   ty: Type::void()
                 };
    }
    return FnType {
        arg_tys: arg_tys,
        ret_ty: ret_ty,
        attrs: attrs,
        sret: sret
    };
}

enum X86_64_ABIInfo { X86_64_ABIInfo }

impl ABIInfo for X86_64_ABIInfo {
    fn compute_info(&self,
                    atys: &[Type],
                    rty: Type,
                    ret_def: bool) -> FnType {
        return x86_64_tys(atys, rty, ret_def);
    }
}

pub fn abi_info() -> @ABIInfo {
    return @X86_64_ABIInfo as @ABIInfo;
}
<commit_msg>librustc: don't skip ahead when computing register types of SSEFloatVectors<commit_after>// Copyright 2012-2013 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.

// The classification code for the x86_64 ABI is taken from the clay language
// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp

use lib::llvm::{llvm, Integer, Pointer, Float, Double};
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute, ByValAttribute};
use middle::trans::cabi::*;

use middle::trans::type_::Type;

use core::option;
use core::option::Option;
use core::uint;
use core::vec;

#[deriving(Eq)]
enum RegClass {
    NoClass,
    Int,
    SSEFs,
    SSEFv,
    SSEDs,
    SSEDv,
    SSEInt,
    SSEUp,
    X87,
    X87Up,
    ComplexX87,
    Memory
}

impl Type {
    fn is_reg_ty(&self) -> bool {
        match self.kind() {
            Integer | Pointer | Float | Double => true,
            _ => false
        }
    }
}

impl RegClass {
    fn is_sse(&self) -> bool {
        match *self {
            SSEFs | SSEFv | SSEDs | SSEDv => true,
            _ => false
        }
    }
}

trait ClassList {
    fn is_pass_byval(&self) -> bool;
    fn is_ret_bysret(&self) -> bool;
}

impl<'self> ClassList for &'self [RegClass] {
    fn is_pass_byval(&self) -> bool {
        if self.len() == 0 { return false; }

        let class = self[0];
           class == Memory
        || class == X87
        || class == ComplexX87
    }

    fn is_ret_bysret(&self) -> bool {
        if self.len() == 0 { return false; }

        self[0] == Memory
    }
}

fn classify_ty(ty: Type) -> ~[RegClass] {
    fn align(off: uint, ty: Type) -> uint {
        let a = ty_align(ty);
        return (off + a - 1u) / a * a;
    }

    fn ty_align(ty: Type) -> uint {
        match ty.kind() {
            Integer => {
                unsafe {
                    ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
                }
            }
            Pointer => 8,
            Float => 4,
            Double => 8,
            Struct => {
              if ty.is_packed() {
                1
              } else {
                let str_tys = ty.field_types();
                str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t)))
              }
            }
            Array => {
                let elt = ty.element_type();
                ty_align(elt)
            }
            _ => fail!("ty_size: unhandled type")
        }
    }

    fn ty_size(ty: Type) -> uint {
        match ty.kind() {
            Integer => {
                unsafe {
                    ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
                }
            }
            Pointer => 8,
            Float => 4,
            Double => 8,
            Struct => {
                let str_tys = ty.field_types();
                if ty.is_packed() {
                    str_tys.iter().fold(0, |s, t| s + ty_size(*t))
                } else {
                    let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
                    align(size, ty)
                }
            }
            Array => {
                let len = ty.array_length();
                let elt = ty.element_type();
                let eltsz = ty_size(elt);
                len * eltsz
            }
            _ => fail!("ty_size: unhandled type")
        }
    }

    fn all_mem(cls: &mut [RegClass]) {
        for uint::range(0, cls.len()) |i| {
            cls[i] = Memory;
        }
    }

    fn unify(cls: &mut [RegClass],
             i: uint,
             newv: RegClass) {
        if cls[i] == newv {
            return;
        } else if cls[i] == NoClass {
            cls[i] = newv;
        } else if newv == NoClass {
            return;
        } else if cls[i] == Memory || newv == Memory {
            cls[i] = Memory;
        } else if cls[i] == Int || newv == Int {
            cls[i] = Int;
        } else if cls[i] == X87 ||
                  cls[i] == X87Up ||
                  cls[i] == ComplexX87 ||
                  newv == X87 ||
                  newv == X87Up ||
                  newv == ComplexX87 {
            cls[i] = Memory;
        } else {
            cls[i] = newv;
        }
    }

    fn classify_struct(tys: &[Type],
                       cls: &mut [RegClass], i: uint,
                       off: uint) {
        let mut field_off = off;
        for tys.iter().advance |ty| {
            field_off = align(field_off, *ty);
            classify(*ty, cls, i, field_off);
            field_off += ty_size(*ty);
        }
    }

    fn classify(ty: Type,
                cls: &mut [RegClass], ix: uint,
                off: uint) {
        let t_align = ty_align(ty);
        let t_size = ty_size(ty);

        let misalign = off % t_align;
        if misalign != 0u {
            let mut i = off / 8u;
            let e = (off + t_size + 7u) / 8u;
            while i < e {
                unify(cls, ix + i, Memory);
                i += 1u;
            }
            return;
        }

        match ty.kind() {
            Integer |
            Pointer => {
                unify(cls, ix + off / 8u, Int);
            }
            Float => {
                if off % 8u == 4u {
                    unify(cls, ix + off / 8u, SSEFv);
                } else {
                    unify(cls, ix + off / 8u, SSEFs);
                }
            }
            Double => {
                unify(cls, ix + off / 8u, SSEDs);
            }
            Struct => {
                classify_struct(ty.field_types(), cls, ix, off);
            }
            Array => {
                let len = ty.array_length();
                let elt = ty.element_type();
                let eltsz = ty_size(elt);
                let mut i = 0u;
                while i < len {
                    classify(elt, cls, ix, off + i * eltsz);
                    i += 1u;
                }
            }
            _ => fail!("classify: unhandled type")
        }
    }

    fn fixup(ty: Type, cls: &mut [RegClass]) {
        let mut i = 0u;
        let ty_kind = ty.kind();
        let e = cls.len();
        if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) {
            if cls[i].is_sse() {
                i += 1u;
                while i < e {
                    if cls[i] != SSEUp {
                        all_mem(cls);
                        return;
                    }
                    i += 1u;
                }
            } else {
                all_mem(cls);
                return
            }
        } else {
            while i < e {
                if cls[i] == Memory {
                    all_mem(cls);
                    return;
                }
                if cls[i] == X87Up {
                    // for darwin
                    // cls[i] = SSEDs;
                    all_mem(cls);
                    return;
                }
                if cls[i] == SSEUp {
                    cls[i] = SSEDv;
                } else if cls[i].is_sse() {
                    i += 1;
                    while i != e && cls[i] == SSEUp { i += 1u; }
                } else if cls[i] == X87 {
                    i += 1;
                    while i != e && cls[i] == X87Up { i += 1u; }
                } else {
                    i += 1;
                }
            }
        }
    }

    let words = (ty_size(ty) + 7) / 8;
    let mut cls = vec::from_elem(words, NoClass);
    if words > 4 {
        all_mem(cls);
        return cls;
    }
    classify(ty, cls, 0, 0);
    fixup(ty, cls);
    return cls;
}

fn llreg_ty(cls: &[RegClass]) -> Type {
    fn llvec_len(cls: &[RegClass]) -> uint {
        let mut len = 1u;
        for cls.iter().advance |c| {
            if *c != SSEUp {
                break;
            }
            len += 1u;
        }
        return len;
    }

    let mut tys = ~[];
    let mut i = 0u;
    let e = cls.len();
    while i < e {
        match cls[i] {
            Int => {
                tys.push(Type::i64());
            }
            SSEFv => {
                let vec_len = llvec_len(cls.tailn(i + 1u));
                let vec_ty = Type::vector(&Type::f32(), (vec_len * 2u) as u64);
                tys.push(vec_ty);
                i += vec_len;
                loop;
            }
            SSEFs => {
                tys.push(Type::f32());
            }
            SSEDs => {
                tys.push(Type::f64());
            }
            _ => fail!("llregtype: unhandled class")
        }
        i += 1u;
    }
    return Type::struct_(tys, false);
}

fn x86_64_tys(atys: &[Type],
              rty: Type,
              ret_def: bool) -> FnType {

    fn x86_64_ty(ty: Type,
                 is_mem_cls: &fn(cls: &[RegClass]) -> bool,
                 attr: Attribute) -> (LLVMType, Option<Attribute>) {

        let (cast, attr, ty) = if !ty.is_reg_ty() {
            let cls = classify_ty(ty);
            if is_mem_cls(cls) {
                (false, option::Some(attr), ty.ptr_to())
            } else {
                (true, option::None, llreg_ty(cls))
            }
        } else {
            (false, option::None, ty)
        };

        (LLVMType { cast: cast, ty: ty }, attr)
    }

    let mut arg_tys = ~[];
    let mut attrs = ~[];
    for atys.iter().advance |t| {
        let (ty, attr) = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute);
        arg_tys.push(ty);
        attrs.push(attr);
    }
    let mut (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(),
                                       StructRetAttribute);
    let sret = ret_attr.is_some();
    if sret {
        arg_tys = vec::append(~[ret_ty], arg_tys);
        ret_ty = LLVMType {
                   cast:  false,
                   ty: Type::void()
                 };
        attrs = vec::append(~[ret_attr], attrs);
    } else if !ret_def {
        ret_ty = LLVMType {
                   cast: false,
                   ty: Type::void()
                 };
    }
    return FnType {
        arg_tys: arg_tys,
        ret_ty: ret_ty,
        attrs: attrs,
        sret: sret
    };
}

enum X86_64_ABIInfo { X86_64_ABIInfo }

impl ABIInfo for X86_64_ABIInfo {
    fn compute_info(&self,
                    atys: &[Type],
                    rty: Type,
                    ret_def: bool) -> FnType {
        return x86_64_tys(atys, rty, ret_def);
    }
}

pub fn abi_info() -> @ABIInfo {
    return @X86_64_ABIInfo as @ABIInfo;
}
<|endoftext|>


<commit_before>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::c_int;

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection, here is the resulting area anyways.
    NoIntersection(Area)
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(x: c_int, y: c_int, width: c_int, height: c_int) -> Self {
        Area(wlr_box { x,
                       y,
                       width,
                       height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: f64, y: f64) -> (f64, f64) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&mut self, other_box: &mut Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty =
                wlr_box_intersection(&mut self.0, &mut other_box.0, &mut (&mut res.0 as *mut _));
            if is_empty {
                IntersectionResult::NoIntersection(res)
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: f64, y: f64) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self, transform: wl_output_transform) -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}
<commit_msg>Added equality impl for Area<commit_after>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::c_int;

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection, here is the resulting area anyways.
    NoIntersection(Area)
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(x: c_int, y: c_int, width: c_int, height: c_int) -> Self {
        Area(wlr_box { x,
                       y,
                       width,
                       height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: f64, y: f64) -> (f64, f64) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&mut self, other_box: &mut Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty =
                wlr_box_intersection(&mut self.0, &mut other_box.0, &mut (&mut res.0 as *mut _));
            if is_empty {
                IntersectionResult::NoIntersection(res)
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: f64, y: f64) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self, transform: wl_output_transform) -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y &&
            self.height == other.height && self.width == other.width
    }
}

impl Eq for Area {}
<|endoftext|>


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

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

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 _)},
});

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

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

#[allow(dead_code)]
#[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,
    Pink       = 13,
    Yellow     = 14,
    White      = 15,
}

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

impl Writer {
    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;
            }
        }
    }

    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: ' ' as u8,
            color_code: self.color_code,
        };
        self.buffer().chars[row] = [blank; BUFFER_WIDTH];
    }
}

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

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

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

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

struct Buffer {
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
<commit_msg>Add #[repr(C)] to ScreenChar<commit_after>use core::ptr::Unique;
use core::fmt;
use spin::Mutex;

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

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 _)},
});

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

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

#[allow(dead_code)]
#[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,
    Pink       = 13,
    Yellow     = 14,
    White      = 15,
}

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

impl Writer {
    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;
            }
        }
    }

    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: ' ' as u8,
            color_code: self.color_code,
        };
        self.buffer().chars[row] = [blank; BUFFER_WIDTH];
    }
}

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

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

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

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

struct Buffer {
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
<|endoftext|>


<commit_before>use regex::Regex;

#[deriving(Show)]
pub enum Token<'a> {
	// tokenize gives:
	Ident(&'a str),
	Const(&'a str),
	Operator(&'a str),
	Newline,
	Whitespace(&'a str),
	Paren(&'a str),
	Colon,
	Equals,
	Period,
}

static IDENT_REGEX: Regex = regex!(r"[a-zA-Z_~']+[a-zA-Z_~0-9']*");
static WHITESPACE_REGEX: Regex = regex!(r"[ \t]+");
static NEWLINE_REGEX: Regex = regex!(r"[\n]+");
static CONST_REGEX: Regex = regex!(r"[0-9]+\.?[0-9]*");
static OPERATOR_REGEX: Regex = regex!(r"\^\^|>=|<=|~=|[\+\*/\^><!%-]|&&|\|\||==|!=");
static PAREN_REGEX: Regex = regex!(r"[\(\)\{\}]|\[|\]");
static COLON_REGEX: Regex = regex!(r":");
static EQUALS_REGEX: Regex = regex!(r"=");
static PERIOD_REGEX: Regex = regex!(r"\.");
static COMMENT_REGEX: Regex = regex!(r"//.*");

pub fn tokenize<'a>(s: &'a str) -> Result<Vec<Token<'a>>, String> {
	let mut walk = s;
	let mut tokens = Vec::new();
	let mut lineindex = 1u;
	let mut linenum = 1u;

	while walk.len() > 0 {
		let mut found = false;

		let ident_match = IDENT_REGEX.find(walk);
		let whitespace_match = WHITESPACE_REGEX.find(walk);
		let newline_match = NEWLINE_REGEX.find(walk);
		let const_match = CONST_REGEX.find(walk);
		let operator_match = OPERATOR_REGEX.find(walk);
		let paren_match = PAREN_REGEX.find(walk);
		let colon_match = COLON_REGEX.find(walk);
		let equals_match = EQUALS_REGEX.find(walk);
		let period_match = PERIOD_REGEX.find(walk);
		let comment_match = COMMENT_REGEX.find(walk);
		if let Some((0, x)) = comment_match { // Strip comments, don't add any tokens
			walk = walk[x..];
			found = true;
		} else if let Some((0, x)) = operator_match {
			tokens.push(Operator(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = ident_match {
			tokens.push(Ident(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = whitespace_match {
			tokens.push(Whitespace(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = newline_match {
			tokens.push(Newline);
			walk = walk[x..];
			found = true;
			linenum += 1;
			lineindex = 0;
		} else if let Some((0, x)) = const_match {
			tokens.push(Const(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = paren_match {
			tokens.push(Paren(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = colon_match {
			tokens.push(Colon);
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = equals_match {
			tokens.push(Equals);
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = period_match {
			tokens.push(Period);
			walk = walk[x..];
			found = true;
			lineindex += x;
		}

		if !found {
			return Err(format!("unrecognized token at line {}:{}", linenum, lineindex));
		}
	}
	Ok(tokens)
}

<commit_msg>Make the lexer return an error struct giving access to line number, column and message<commit_after>use regex::Regex;
use std::fmt;

#[deriving(Show)]
pub enum Token<'a> {
	// tokenize gives:
	Ident(&'a str),
	Const(&'a str),
	Operator(&'a str),
	Newline,
	Whitespace(&'a str),
	Paren(&'a str),
	Colon,
	Equals,
	Period,
}

pub struct LexError {
    pub msg: &'static str,
    pub line_num: uint,
    pub col_num: uint,
}

impl fmt::Show for LexError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "At line {}:{} -> {}", self.line_num, self.col_num, self.msg)
    }
}

static IDENT_REGEX: Regex = regex!(r"[a-zA-Z_~']+[a-zA-Z_~0-9']*");
static WHITESPACE_REGEX: Regex = regex!(r"[ \t]+");
static NEWLINE_REGEX: Regex = regex!(r"[\n]+");
static CONST_REGEX: Regex = regex!(r"[0-9]+\.?[0-9]*");
static OPERATOR_REGEX: Regex = regex!(r"\^\^|>=|<=|~=|[\+\*/\^><!%-]|&&|\|\||==|!=");
static PAREN_REGEX: Regex = regex!(r"[\(\)\{\}]|\[|\]");
static COLON_REGEX: Regex = regex!(r":");
static EQUALS_REGEX: Regex = regex!(r"=");
static PERIOD_REGEX: Regex = regex!(r"\.");
static COMMENT_REGEX: Regex = regex!(r"//.*");

pub fn tokenize<'a>(s: &'a str) -> Result<Vec<Token<'a>>, LexError> {
	let mut walk = s;
	let mut tokens = Vec::new();
	let mut lineindex = 1u;
	let mut linenum = 1u;

	while walk.len() > 0 {
		let mut found = false;

		let ident_match = IDENT_REGEX.find(walk);
		let whitespace_match = WHITESPACE_REGEX.find(walk);
		let newline_match = NEWLINE_REGEX.find(walk);
		let const_match = CONST_REGEX.find(walk);
		let operator_match = OPERATOR_REGEX.find(walk);
		let paren_match = PAREN_REGEX.find(walk);
		let colon_match = COLON_REGEX.find(walk);
		let equals_match = EQUALS_REGEX.find(walk);
		let period_match = PERIOD_REGEX.find(walk);
		let comment_match = COMMENT_REGEX.find(walk);
		if let Some((0, x)) = comment_match { // Strip comments, don't add any tokens
			walk = walk[x..];
			found = true;
		} else if let Some((0, x)) = operator_match {
			tokens.push(Operator(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = ident_match {
			tokens.push(Ident(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = whitespace_match {
			tokens.push(Whitespace(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = newline_match {
			tokens.push(Newline);
			walk = walk[x..];
			found = true;
			linenum += 1;
			lineindex = 0;
		} else if let Some((0, x)) = const_match {
			tokens.push(Const(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = paren_match {
			tokens.push(Paren(walk[0..x]));
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = colon_match {
			tokens.push(Colon);
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = equals_match {
			tokens.push(Equals);
			walk = walk[x..];
			found = true;
			lineindex += x;
		} else if let Some((0, x)) = period_match {
			tokens.push(Period);
			walk = walk[x..];
			found = true;
			lineindex += x;
		}

		if !found {
			return Err(LexError { msg: "unrecognized token", line_num: linenum, col_num: lineindex });
		}
	}
	Ok(tokens)
}

<|endoftext|>


<commit_before>// helper for transmutation, shown below.
type RustClosure = (int,int);

struct Condition {
    key: task::local_data::LocalDataKey<Handler>
}

struct Handler {
    handle: RustClosure,
    prev: Option<@Handler>
}

struct ProtectBlock {
    cond: &Condition,
    inner: RustClosure
}

struct PopHandler {
    cond: &Condition,
    drop {
        unsafe {
            debug!("PopHandler: popping handler from TLS");
            match task::local_data::local_data_pop(self.cond.key) {
                None => (),
                Some(h) => {
                    match h.prev {
                        None => (),
                        Some(p) =>
                        task::local_data::local_data_set(self.cond.key, p)
                    }
                }
            }
        }
    }
}

struct HandleBlock {
    pb: &ProtectBlock,
    handler: @Handler,
    drop {
        unsafe {
            debug!("HandleBlock: pushing handler to TLS");
            task::local_data::local_data_set(self.pb.cond.key,
                                             self.handler);
            let _pop = PopHandler { cond: self.pb.cond };
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            let f : &fn() = ::cast::transmute(self.pb.inner);
            debug!("HandleBlock: invoking protected code");
            f();
            debug!("HandleBlock: returned from protected code");
        }
    }
}

impl ProtectBlock {
    fn handle<T, U: Copy>(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self {
        unsafe {
            debug!("ProtectBlock.handle: setting up handler block");
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.cond.key);
            HandleBlock { pb: self,
                          handler: @Handler{handle: *p, prev: prev} }
        }
    }
}

impl Condition {

    fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self {
        unsafe {
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            debug!("Condition.protect: setting up protected block");
            let p : *RustClosure = ::cast::transmute(&inner);
            ProtectBlock { cond: self,
                           inner: *p }
        }
    }

    fn raise<T, U: Copy>(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_get(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
                    f(t)
                }
            }
        }
    }
}

#[cfg(test)]
fn happiness_key(_x: @Handler) { }

#[cfg(test)]
fn sadness_key(_x: @Handler) { }

#[cfg(test)]
fn trouble(i: int) {
    // Condition should work as a const, just limitations in consts.
    let sadness_condition : Condition = Condition { key: sadness_key };
    debug!("trouble: raising conition");
    let j = sadness_condition.raise(&i);
    debug!("trouble: handler recovered with %d", j);
}

#[test]
fn test1() {

    let sadness_condition : Condition = Condition { key: sadness_key };

    let mut i = 10;

    let b = do sadness_condition.protect {
        debug!("test1: in protected block");
        trouble(1);
        trouble(2);
        trouble(3);
    };

    do b.handle |j| {
        debug!("test1: in handler");
        i += *j;
        i
    };

    assert i == 16;
}
#[cfg(test)]
fn nested_test_inner() {
    let sadness_condition : Condition = Condition { key: sadness_key };

    let mut inner_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_inner: in protected block");
        trouble(1);
    };

    do b.handle |_j:&int| {
        debug!("nested_test_inner: in handler");
        inner_trapped = true;
        0
    };

    assert inner_trapped;
}

#[test]
fn nested_test_outer() {

    let sadness_condition : Condition = Condition { key: sadness_key };

    let mut outer_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_outer: in protected block");
        nested_test_inner();
        trouble(1);
    };

    do b.handle |_j:&int| {
        debug!("nested_test_outer: in handler");
        outer_trapped = true;
        0
    };

    assert outer_trapped;
}
<commit_msg>core: Add type params to condition handling so interface is safe.<commit_after>// helper for transmutation, shown below.
type RustClosure = (int,int);

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

struct Handler<T, U:Copy> {
    handle: RustClosure,
    prev: Option<@Handler<T, U>>
}

struct ProtectBlock<T, U:Copy> {
    cond: &Condition<T, U>,
    inner: RustClosure
}

struct PopHandler<T, U:Copy> {
    cond: &Condition<T,U>,
    drop {
        unsafe {
            debug!("PopHandler: popping handler from TLS");
            match task::local_data::local_data_pop(self.cond.key) {
                None => (),
                Some(h) => {
                    match h.prev {
                        None => (),
                        Some(p) =>
                        task::local_data::local_data_set(self.cond.key, p)
                    }
                }
            }
        }
    }
}

struct HandleBlock<T, U:Copy> {
    pb: &ProtectBlock<T,U>,
    handler: @Handler<T,U>,
    drop {
        unsafe {
            debug!("HandleBlock: pushing handler to TLS");
            task::local_data::local_data_set(self.pb.cond.key,
                                             self.handler);
            let _pop = PopHandler { cond: self.pb.cond };
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            let f : &fn() = ::cast::transmute(self.pb.inner);
            debug!("HandleBlock: invoking protected code");
            f();
            debug!("HandleBlock: returned from protected code");
        }
    }
}

impl<T, U: Copy> ProtectBlock<T,U> {
    fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self<T,U> {
        unsafe {
            debug!("ProtectBlock.handle: setting up handler block");
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.cond.key);
            HandleBlock { pb: self,
                          handler: @Handler{handle: *p, prev: prev} }
        }
    }
}

impl<T, U: Copy>  Condition<T,U> {

    fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self<T,U> {
        unsafe {
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            debug!("Condition.protect: setting up protected block");
            let p : *RustClosure = ::cast::transmute(&inner);
            ProtectBlock { cond: self,
                           inner: *p }
        }
    }

    fn raise(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_get(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
                    f(t)
                }
            }
        }
    }
}

#[cfg(test)]
fn sadness_key(_x: @Handler<int,int>) { }

#[cfg(test)]
fn trouble(i: int) {
    // Condition should work as a const, just limitations in consts.
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };
    debug!("trouble: raising conition");
    let j = sadness_condition.raise(&i);
    debug!("trouble: handler recovered with %d", j);
}

#[test]
fn test1() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut i = 10;

    let b = do sadness_condition.protect {
        debug!("test1: in protected block");
        trouble(1);
        trouble(2);
        trouble(3);
    };

    do b.handle |j| {
        debug!("test1: in handler");
        i += *j;
        i
    };

    assert i == 16;
}
#[cfg(test)]
fn nested_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_inner: in protected block");
        trouble(1);
    };

    do b.handle |_j:&int| {
        debug!("nested_test_inner: in handler");
        inner_trapped = true;
        0
    };

    assert inner_trapped;
}

#[test]
fn nested_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_outer: in protected block");
        nested_test_inner();
        trouble(1);
    };

    do b.handle |_j:&int| {
        debug!("nested_test_outer: in handler");
        outer_trapped = true;
        0
    };

    assert outer_trapped;
}
<|endoftext|>