<commit_before>use super::{ffi, consts, GetSockOpt, SetSockOpt};
use {Errno, Result};
use sys::time::TimeVal;
use libc::{c_int, uint8_t, c_void, socklen_t};
use std::mem;
use std::os::unix::io::RawFd;

macro_rules! setsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        impl SetSockOpt for $name {
            type Val = $ty;

            fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
                unsafe {
                    let setter: $setter = Set::new(val);

                    let res = ffi::setsockopt(fd, $level, $flag,
                                              setter.ffi_ptr(),
                                              setter.ffi_len());
                    Errno::result(res).map(drop)
                }
            }
        }
    }
}

macro_rules! getsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        impl GetSockOpt for $name {
            type Val = $ty;

            fn get(&self, fd: RawFd) -> Result<$ty> {
                unsafe {
                    let mut getter: $getter = Get::blank();

                    let res = ffi::getsockopt(fd, $level, $flag,
                                              getter.ffi_ptr(),
                                              getter.ffi_len());
                    try!(Errno::result(res));

                    Ok(getter.unwrap())
                }
            }
        }
    }
}

// Helper to generate the sockopt accessors
macro_rules! sockopt_impl {
    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (Both, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
    };

    (Both, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
    };
}

/*
 *
 * ===== Define sockopts =====
 *
 */

sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool);
sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool);
sockopt_impl!(Both, TcpNoDelay, consts::IPPROTO_TCP, consts::TCP_NODELAY, bool);
sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger);
sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd")))]
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd")))]
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd"))]
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_JOIN_GROUP, super::ipv6_mreq);
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd"))]
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_LEAVE_GROUP, super::ipv6_mreq);
sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8);
sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool);
sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal);
sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal);
sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool);
sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool);
sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32);
sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool);
#[cfg(target_os = "linux")]
sockopt_impl!(GetOnly, PeerCredentials, consts::SOL_SOCKET, consts::SO_PEERCRED, super::ucred);
#[cfg(any(target_os = "macos",
          target_os = "ios"))]
sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32);
#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "linux",
          target_os = "android",
          target_os = "nacl"))]
sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32);

/*
 *
 * ===== Accessor helpers =====
 *
 */

trait Get<T> {
    unsafe fn blank() -> Self;
    unsafe fn ffi_ptr(&mut self) -> *mut c_void;
    unsafe fn ffi_len(&mut self) -> *mut socklen_t;
    unsafe fn unwrap(self) -> T;
}

trait Set<'a, T> {
    fn new(val: &'a T) -> Self;
    unsafe fn ffi_ptr(&self) -> *const c_void;
    unsafe fn ffi_len(&self) -> socklen_t;
}

struct GetStruct<T> {
    len: socklen_t,
    val: T,
}

impl<T> Get<T> for GetStruct<T> {
    unsafe fn blank() -> Self {
        GetStruct {
            len: mem::size_of::<T>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> T {
        assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
        self.val
    }
}

struct SetStruct<'a, T: 'static> {
    ptr: &'a T,
}

impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
    fn new(ptr: &'a T) -> SetStruct<'a, T> {
        SetStruct { ptr: ptr }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(self.ptr)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<T>() as socklen_t
    }
}

struct GetBool {
    len: socklen_t,
    val: c_int,
}

impl Get<bool> for GetBool {
    unsafe fn blank() -> Self {
        GetBool {
            len: mem::size_of::<c_int>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> bool {
        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
        self.val != 0
    }
}

struct SetBool {
    val: c_int,
}

impl<'a> Set<'a, bool> for SetBool {
    fn new(val: &'a bool) -> SetBool {
        SetBool { val: if *val { 1 } else { 0 } }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

struct GetU8 {
    len: socklen_t,
    val: uint8_t,
}

impl Get<u8> for GetU8 {
    unsafe fn blank() -> Self {
        GetU8 {
            len: mem::size_of::<uint8_t>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> u8 {
        assert!(self.len as usize == mem::size_of::<uint8_t>(), "invalid getsockopt implementation");
        self.val as u8
    }
}

struct SetU8 {
    val: uint8_t,
}

impl<'a> Set<'a, u8> for SetU8 {
    fn new(val: &'a u8) -> SetU8 {
        SetU8 { val: *val as uint8_t }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

#[cfg(test)]
mod test {
    #[cfg(target_os = "linux")]
    #[test]
    fn can_get_peercred_on_unix_socket() {
        use super::super::*;

        let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, 0, SockFlag::empty()).unwrap();
        let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
        let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
        assert_eq!(a_cred, b_cred);
        assert!(a_cred.pid != 0);
    }
}
<commit_msg>Add support for SO_{RCV,SND}BUF(FORCE)? sockopts<commit_after>use super::{ffi, consts, GetSockOpt, SetSockOpt};
use {Errno, Result};
use sys::time::TimeVal;
use libc::{c_int, uint8_t, c_void, socklen_t};
use std::mem;
use std::os::unix::io::RawFd;

macro_rules! setsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        impl SetSockOpt for $name {
            type Val = $ty;

            fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
                unsafe {
                    let setter: $setter = Set::new(val);

                    let res = ffi::setsockopt(fd, $level, $flag,
                                              setter.ffi_ptr(),
                                              setter.ffi_len());
                    Errno::result(res).map(drop)
                }
            }
        }
    }
}

macro_rules! getsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        impl GetSockOpt for $name {
            type Val = $ty;

            fn get(&self, fd: RawFd) -> Result<$ty> {
                unsafe {
                    let mut getter: $getter = Get::blank();

                    let res = ffi::getsockopt(fd, $level, $flag,
                                              getter.ffi_ptr(),
                                              getter.ffi_len());
                    try!(Errno::result(res));

                    Ok(getter.unwrap())
                }
            }
        }
    }
}

// Helper to generate the sockopt accessors
macro_rules! sockopt_impl {
    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (Both, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
    };

    (Both, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
    };

    (Both, $name:ident, $level:path, $flag:path, usize) => {
        sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
    };
}

/*
 *
 * ===== Define sockopts =====
 *
 */

sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool);
sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool);
sockopt_impl!(Both, TcpNoDelay, consts::IPPROTO_TCP, consts::TCP_NODELAY, bool);
sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger);
sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd")))]
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd")))]
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd"))]
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_JOIN_GROUP, super::ipv6_mreq);
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd"))]
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_LEAVE_GROUP, super::ipv6_mreq);
sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8);
sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool);
sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal);
sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal);
sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool);
sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool);
sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32);
sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool);
#[cfg(target_os = "linux")]
sockopt_impl!(GetOnly, PeerCredentials, consts::SOL_SOCKET, consts::SO_PEERCRED, super::ucred);
#[cfg(any(target_os = "macos",
          target_os = "ios"))]
sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32);
#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "linux",
          target_os = "android",
          target_os = "nacl"))]
sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32);
sockopt_impl!(Both, RcvBuf, consts::SOL_SOCKET, consts::SO_RCVBUF, usize);
sockopt_impl!(Both, SndBuf, consts::SOL_SOCKET, consts::SO_SNDBUF, usize);
#[cfg(target_os = "linux")]
sockopt_impl!(SetOnly, RcvBufForce, consts::SOL_SOCKET, consts::SO_RCVBUFFORCE, usize);
#[cfg(target_os = "linux")]
sockopt_impl!(SetOnly, SndBufForce, consts::SOL_SOCKET, consts::SO_SNDBUFFORCE, usize);

/*
 *
 * ===== Accessor helpers =====
 *
 */

trait Get<T> {
    unsafe fn blank() -> Self;
    unsafe fn ffi_ptr(&mut self) -> *mut c_void;
    unsafe fn ffi_len(&mut self) -> *mut socklen_t;
    unsafe fn unwrap(self) -> T;
}

trait Set<'a, T> {
    fn new(val: &'a T) -> Self;
    unsafe fn ffi_ptr(&self) -> *const c_void;
    unsafe fn ffi_len(&self) -> socklen_t;
}

struct GetStruct<T> {
    len: socklen_t,
    val: T,
}

impl<T> Get<T> for GetStruct<T> {
    unsafe fn blank() -> Self {
        GetStruct {
            len: mem::size_of::<T>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> T {
        assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
        self.val
    }
}

struct SetStruct<'a, T: 'static> {
    ptr: &'a T,
}

impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
    fn new(ptr: &'a T) -> SetStruct<'a, T> {
        SetStruct { ptr: ptr }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(self.ptr)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<T>() as socklen_t
    }
}

struct GetBool {
    len: socklen_t,
    val: c_int,
}

impl Get<bool> for GetBool {
    unsafe fn blank() -> Self {
        GetBool {
            len: mem::size_of::<c_int>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> bool {
        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
        self.val != 0
    }
}

struct SetBool {
    val: c_int,
}

impl<'a> Set<'a, bool> for SetBool {
    fn new(val: &'a bool) -> SetBool {
        SetBool { val: if *val { 1 } else { 0 } }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

struct GetU8 {
    len: socklen_t,
    val: uint8_t,
}

impl Get<u8> for GetU8 {
    unsafe fn blank() -> Self {
        GetU8 {
            len: mem::size_of::<uint8_t>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> u8 {
        assert!(self.len as usize == mem::size_of::<uint8_t>(), "invalid getsockopt implementation");
        self.val as u8
    }
}

struct SetU8 {
    val: uint8_t,
}

impl<'a> Set<'a, u8> for SetU8 {
    fn new(val: &'a u8) -> SetU8 {
        SetU8 { val: *val as uint8_t }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

struct GetUsize {
    len: socklen_t,
    val: c_int,
}

impl Get<usize> for GetUsize {
    unsafe fn blank() -> Self {
        GetUsize {
            len: mem::size_of::<c_int>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> usize {
        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
        self.val as usize
    }
}

struct SetUsize {
    val: c_int,
}

impl<'a> Set<'a, usize> for SetUsize {
    fn new(val: &'a usize) -> SetUsize {
        SetUsize { val: *val as c_int }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

#[cfg(test)]
mod test {
    #[cfg(target_os = "linux")]
    #[test]
    fn can_get_peercred_on_unix_socket() {
        use super::super::*;

        let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, 0, SockFlag::empty()).unwrap();
        let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
        let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
        assert_eq!(a_cred, b_cred);
        assert!(a_cred.pid != 0);
    }
}
<|endoftext|>


<commit_before>use std::borrow::{Borrow, BorrowMut};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{mem, ptr, str};
use ::utf8::PascalStr;
use ::PASCAL_STRING_BUF_SIZE;

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length *of the number of bytes used*.
///
/// Note that because this string type is utf8 encoded, the first byte will not store the number of characters
/// in the string.
pub struct PascalString {
    /// The number of bytes used in the string.
    len: u8,
    /// The internal character buffer, encoded in utf8
    chars_buf: [u8; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    #[inline]
    pub fn from(s: &str) -> Self {
        unimplemented!()
    }

    #[inline]
    pub fn push(&mut self, ch: char) {
        self.try_push(ch).unwrap()
    }

    pub fn try_push(&mut self, ch: char) -> Result<(), PascalStringAppendError> {
        let unich = UniChar::from(ch);
        unimplemented!();
    }

    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: &S) {
        self.try_push_str(s).unwrap()
    }

    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: &S) -> Result<(), PascalStringAppendError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
        unimplemented!()
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars_buf: [0u8; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars_buf, &mut clone.chars_buf, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Hash for PascalString {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(&self.chars_buf);
    }
}

impl Deref for PascalString {
    type Target = PascalStr;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { mem::transmute(&self.chars_buf[0..(self.len as usize)]) }
    }
}

impl DerefMut for PascalString {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(&mut self.chars_buf[0..(self.len as usize)]) }
    }
}

#[derive(Debug)]
pub enum PascalStringAppendError {
    NoRoom,
}

/// A view into the individual bytes that make up a `char`.
///
/// Use the `From` trait to convert a `char` to a `UniChar` without using `unsafe`.
#[derive(Clone, Copy, Default, Eq, PartialEq)]
struct UniChar {
    /// First byte.
    b0: u8,
    /// Second byte.
    b1: u8,
    /// Third byte.
    b2: u8,
    /// Fourth byte.
    b3: u8
}

impl UniChar {
    fn num_bytes(&self) -> u8 {
        unimplemented!()
    }
}

impl From<char> for UniChar {
    fn from(ch: char) -> Self {
        let chn: u32 = ch as u32;
        UniChar {
            b0: ((chn & 0xff000000u32) >> 24) as u8,
            b1: ((chn & 0x00ff0000u32) >> 16) as u8,
            b2: ((chn & 0x0000ff00u32) >> 8) as u8,
            b3:  (chn & 0x000000ffu32) as u8
        }
    }
}

<commit_msg>implement PascalString::try_push<commit_after>use std::borrow::{Borrow, BorrowMut};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{mem, ptr, str};
use odds::char::{encode_utf8, EncodeUtf8Error};
use ::utf8::PascalStr;
use ::PASCAL_STRING_BUF_SIZE;

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length *of the number of bytes used*.
///
/// Note that because this string type is utf8 encoded, the first byte will not store the number of characters
/// in the string.
pub struct PascalString {
    /// The number of bytes used in the string.
    len: u8,
    /// The internal character buffer, encoded in utf8
    chars_buf: [u8; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    #[inline]
    pub fn from(s: &str) -> Self {
        unimplemented!()
    }

    #[inline]
    pub fn push(&mut self, ch: char) {
        self.try_push(ch).unwrap()
    }

    #[inline]
    pub fn try_push(&mut self, ch: char) -> Result<(), EncodeUtf8Error> {
        let num_bytes_extended = try!(encode_utf8(ch, &mut self.chars_buf[self.len as usize..]));
        self.len += num_bytes_extended as u8;
        Ok(())
    }

    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: &S) {
        self.try_push_str(s).unwrap()
    }

    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: &S) -> Result<(), PascalStringAppendError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
        unimplemented!()
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars_buf: [0u8; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars_buf, &mut clone.chars_buf, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Hash for PascalString {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(&self.chars_buf);
    }
}

impl Deref for PascalString {
    type Target = PascalStr;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { mem::transmute(&self.chars_buf[0..(self.len as usize)]) }
    }
}

impl DerefMut for PascalString {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(&mut self.chars_buf[0..(self.len as usize)]) }
    }
}

#[derive(Debug)]
pub enum PascalStringAppendError {
    NoRoom,
}

/// A view into the individual bytes that make up a `char`.
///
/// Use the `From` trait to convert a `char` to a `UniChar` without using `unsafe`.
#[derive(Clone, Copy, Default, Eq, PartialEq)]
struct UniChar {
    /// First byte.
    b0: u8,
    /// Second byte.
    b1: u8,
    /// Third byte.
    b2: u8,
    /// Fourth byte.
    b3: u8
}

impl UniChar {
    fn num_bytes(&self) -> u8 {
        unimplemented!()
    }
}

impl From<char> for UniChar {
    fn from(ch: char) -> Self {
        let chn: u32 = ch as u32;
        UniChar {
            b0: ((chn & 0xff000000u32) >> 24) as u8,
            b1: ((chn & 0x00ff0000u32) >> 16) as u8,
            b2: ((chn & 0x0000ff00u32) >> 8) as u8,
            b3:  (chn & 0x000000ffu32) as u8
        }
    }
}

<|endoftext|>


<commit_before>use std::rc::{Rc};
use std::default::{Default};
use std::u16;
use glium;

pub struct Buffer {
    shader: Rc<glium::Program>,
    texture: Rc<glium::texture::Texture2d>,
    vertices: Vec<Vertex>,
    indices: Vec<u16>,
}

impl Buffer {
    pub fn new(shader: Rc<glium::Program>, texture: Rc<glium::texture::Texture2d>) -> Buffer {
        Buffer {
            shader: shader,
            texture: texture,
            vertices: Vec::new(),
            indices: Vec::new(),
        }
    }

    pub fn should_flush(&self) -> bool {
        // When you're getting within an order of magnitude of the u16 max
        // limit it's time to flush.
        self.vertices.len() > 1<<15
    }

    pub fn push(&mut self, vertices: Vec<Vertex>, faces: Vec<[u16; 3]>) {
        assert!(self.vertices.len() + vertices.len() < u16::MAX as usize);
        let offset = self.vertices.len() as u16;
        for v in vertices.into_iter() { self.vertices.push(v); }

        for face in faces.into_iter() {
            for i in face.into_iter() {
                self.indices.push(i + offset);
            }
        }
    }

    pub fn flush<S>(&mut self, display: &glium::Display, target: &mut S)
        where S: glium::Surface {
        // Extract the geometry accumulation buffers and convert into
        // temporary Glium buffers.
        let vertices = glium::VertexBuffer::new(display, &self.vertices).unwrap();
        let indices = glium::IndexBuffer::new(
            display, glium::index::PrimitiveType::TrianglesList, &self.indices).unwrap();

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&*self.texture, glium::uniforms::SamplerBehavior {
                magnify_filter: glium::uniforms::MagnifySamplerFilter::Nearest,
                .. Default::default() }));

        let params = glium::DrawParameters {
            backface_culling: glium::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::DepthTest::IfLessOrEqual,
            depth_write: true,
            blending_function: Some(glium::BlendingFunction::Addition {
                source: glium::LinearBlendingFactor::SourceAlpha,
                destination: glium::LinearBlendingFactor::OneMinusSourceAlpha }),
            .. Default::default() };

        target.draw(&vertices, &indices, &*self.shader, &uniforms, &params).unwrap();

        self.vertices.clear();
        self.indices.clear();
    }
}

#[derive(Copy, Clone)]
/// Geometry vertex in on-screen graphics.
pub struct Vertex {
    /// Coordinates on screen
    pub pos: [f32; 3],
    /// Texture coordinates
    pub tex_coord: [f32; 2],
    /// Color for the light parts of the texture
    pub color: [f32; 4],
    /// Color for the dark parts of the texture
    pub back_color: [f32; 4],
}
implement_vertex!(Vertex, pos, tex_coord, color, back_color);
<commit_msg>Construct mesh buffer with default shader<commit_after>use std::rc::{Rc};
use std::default::{Default};
use std::u16;
use image;
use glium;

pub struct Buffer {
    shader: Rc<glium::Program>,
    texture: Rc<glium::texture::Texture2d>,
    vertices: Vec<Vertex>,
    indices: Vec<u16>,
}

impl Buffer {
    /// Create a mesh render buffer with shared shader and texture.
    pub fn new_shared(shader: Rc<glium::Program>, texture: Rc<glium::texture::Texture2d>) -> Buffer {
        Buffer {
            shader: shader,
            texture: texture,
            vertices: Vec::new(),
            indices: Vec::new(),
        }
    }

    /// Create a mesh render buffer with locally owned shader and texture.
    /// This uses the default sprite shader.
    pub fn new<'a, T>(display: &glium::Display, atlas_image: T) -> Buffer
        where T: glium::texture::Texture2dDataSource<'a> {
        Buffer::new_shared(
            Rc::new(glium::Program::from_source(
                display,
                include_str!("sprite.vert"),
                include_str!("sprite.frag"),
                None).unwrap()),
            Rc::new(glium::texture::Texture2d::new(
                display, atlas_image).unwrap()))
    }

    pub fn should_flush(&self) -> bool {
        // When you're getting within an order of magnitude of the u16 max
        // limit it's time to flush.
        self.vertices.len() > 1<<15
    }

    pub fn push(&mut self, vertices: Vec<Vertex>, faces: Vec<[u16; 3]>) {
        assert!(self.vertices.len() + vertices.len() < u16::MAX as usize);
        let offset = self.vertices.len() as u16;
        for v in vertices.into_iter() { self.vertices.push(v); }

        for face in faces.into_iter() {
            for i in face.into_iter() {
                self.indices.push(i + offset);
            }
        }
    }

    pub fn flush<S>(&mut self, display: &glium::Display, target: &mut S)
        where S: glium::Surface {
        // Extract the geometry accumulation buffers and convert into
        // temporary Glium buffers.
        let vertices = glium::VertexBuffer::new(display, &self.vertices).unwrap();
        let indices = glium::IndexBuffer::new(
            display, glium::index::PrimitiveType::TrianglesList, &self.indices).unwrap();

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&*self.texture, glium::uniforms::SamplerBehavior {
                magnify_filter: glium::uniforms::MagnifySamplerFilter::Nearest,
                .. Default::default() }));

        let params = glium::DrawParameters {
            backface_culling: glium::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::DepthTest::IfLessOrEqual,
            depth_write: true,
            blending_function: Some(glium::BlendingFunction::Addition {
                source: glium::LinearBlendingFactor::SourceAlpha,
                destination: glium::LinearBlendingFactor::OneMinusSourceAlpha }),
            .. Default::default() };

        target.draw(&vertices, &indices, &*self.shader, &uniforms, &params).unwrap();

        self.vertices.clear();
        self.indices.clear();
    }
}

#[derive(Copy, Clone)]
/// Geometry vertex in on-screen graphics.
pub struct Vertex {
    /// Coordinates on screen
    pub pos: [f32; 3],
    /// Texture coordinates
    pub tex_coord: [f32; 2],
    /// Color for the light parts of the texture
    pub color: [f32; 4],
    /// Color for the dark parts of the texture
    pub back_color: [f32; 4],
}
implement_vertex!(Vertex, pos, tex_coord, color, back_color);
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::path::{Path};
use std::iter::{repeat};
use std::cmp;
use std::collections::HashMap;
use stb_tt::{Font};
use cgmath::{Vector3, Vector2};
use common::types::{Size2, ZInt, ZFloat};
use common::fs;
use misc::{add_quad_to_vec};
use texture::{Texture};
use types::{VertexCoord, TextureCoord, ScreenPos};
use mesh::{Mesh};
use zgl::{Zgl};

#[derive(Clone)]
pub struct Glyph {
    pos: ScreenPos,
    size: Size2<ZInt>,
    xoff: ZInt,
    yoff: ZInt,
}

pub struct FontStash {
    size: ZFloat,
    font: Font,
    texture: Texture,
    texture_size: ZInt,
    pos: ScreenPos,
    glyphs: HashMap<char, Glyph>,
    max_h: ZInt,
}

impl FontStash {
    #[allow(deprecated)] // TODO: remove
    pub fn new(zgl: &Zgl, font_path: &Path, size: ZFloat) -> FontStash {
        use std::old_io::{MemReader};

        let texture_size = 1024;
        let mut mem_reader = MemReader::new(fs::load(font_path).into_inner());
        let font = Font::from_reader(&mut mem_reader, size);
        let texture = Texture::new_empty(
            zgl, Size2{w: texture_size, h: texture_size});
        FontStash {
            size: size,
            font: font,
            texture: texture,
            texture_size: texture_size,
            pos: ScreenPos{v: Vector2{x: 0, y: 0}},
            glyphs: HashMap::new(),
            max_h: 0,
        }
    }

    pub fn get_glyph(&mut self, zgl: &Zgl, c: char) -> Glyph {
        if let Some(r) = self.glyphs.get(&c) {
            return r.clone();
        }
        self.add_glyph(zgl, c)
    }

    pub fn get_size(&self) -> ZFloat {
        self.size
    }

    pub fn get_text_size(&mut self, zgl: &Zgl, text: &str) -> (ScreenPos, Size2<ZInt>) {
        let mut size = Size2{w: 0, h: 0};
        let mut pos = ScreenPos{v: Vector2{x: 0, y: 0}};
        for c in text.chars() {
            let glyph = self.get_glyph(zgl, c);
            let w = glyph.size.w;
            let h = glyph.size.h;
            let yoff = -glyph.yoff;
            if pos.v.y > yoff - h {
                pos.v.y = yoff - h;
            }
            if size.h < yoff {
                size.h = yoff;
            }
            size.w += w + glyph.xoff;
        }
        (pos, size)
    }

    // TODO: fix centred hack
    pub fn get_mesh(&mut self, zgl: &Zgl, text: &str, centred: bool) -> Mesh {
        let mut vertex_data = Vec::new();
        let mut tex_data = Vec::new();
        let s = self.texture_size as ZFloat;
        let mut i = if centred {
            let (_, Size2{w, h: _}) = self.get_text_size(zgl, text);
            (-w / 2) as ZFloat
        } else {
            0.0
        };
        for c in text.chars() {
            let glyph = self.get_glyph(zgl, c);
            let w = glyph.size.w as ZFloat;
            let h = glyph.size.h as ZFloat;
            let x1 = glyph.pos.v.x as ZFloat / s;
            let y1 = glyph.pos.v.y as ZFloat / s;
            let x2 = x1 + w / s;
            let y2 = y1 + h / s;
            add_quad_to_vec(
                &mut tex_data,
                TextureCoord{v: Vector2{x: x1, y: y1}},
                TextureCoord{v: Vector2{x: x1, y: y2}},
                TextureCoord{v: Vector2{x: x2, y: y2}},
                TextureCoord{v: Vector2{x: x2, y: y1}},
            );
            let yoff = -glyph.yoff as ZFloat;
            add_quad_to_vec(
                &mut vertex_data,
                VertexCoord{v: Vector3{x: i, y: yoff, z: 0.0}},
                VertexCoord{v: Vector3{x: i, y: yoff - h, z: 0.0}},
                VertexCoord{v: Vector3{x: w + i, y: yoff - h, z: 0.0}},
                VertexCoord{v: Vector3{x: w + i, y: yoff, z: 0.0}},
            );
            i += w + glyph.xoff as ZFloat;
        }
        let mut mesh = Mesh::new(zgl, vertex_data.as_slice());
        // TODO: remove 'clone()'?
        mesh.add_texture(zgl, self.texture.clone(), tex_data.as_slice());
        mesh
    }

    fn insert_image_to_cache(
        &mut self,
        zgl: &Zgl,
        pos: ScreenPos,
        size: Size2<ZInt>,
        bitmap: Vec<u8>
    ) {
        let mut data: Vec<_> = repeat(0u8)
            .take((size.w * size.h) as usize * 4).collect();
        for y in range(0, size.h) {
            for x in range(0, size.w) {
                let n = (x + y * size.w) as usize * 4;
                data[n + 0] = 255;
                data[n + 1] = 255;
                data[n + 2] = 255;
                data[n + 3] = bitmap[(x + y * size.w) as usize];
            }
        }
        self.texture.bind(zgl);
        self.texture.set_sub_image(zgl, pos.v, size, &data);
    }

    fn start_new_row(&mut self) {
        self.pos.v.y += self.max_h;
        self.pos.v.x = 0;
        self.max_h = 0;
        assert!(self.pos.v.y < self.texture_size);
    }

    fn add_glyph(&mut self, zgl: &Zgl, c: char) -> Glyph {
        assert!(self.glyphs.get(&c).is_none());
        let index = self.font.find_glyph_index(c);
        let (bitmap, w, h, xoff, yoff) = self.font.get_glyph(index);
        if self.pos.v.x + w > self.texture_size {
            self.start_new_row();
        }
        self.pos.v.y = cmp::max(h, self.pos.v.y);
        let pos = self.pos.clone();
        let size = Size2{w: w, h: h};
        if w * h != 0 {
            self.insert_image_to_cache(zgl, pos.clone(), size.clone(), bitmap);
        }
        let xoff = if c == ' ' {
            let space_width = (self.size / 3.0) as ZInt; // TODO: get from ttf
            xoff + space_width
        } else {
            xoff
        };
        self.pos.v.x += w;
        let glyph = Glyph {
            pos: pos,
            size: size,
            xoff: xoff,
            yoff: yoff,
        };
        if self.max_h < h - yoff {
            self.max_h = h - yoff;
        }
        self.glyphs.insert(c, glyph.clone());
        glyph
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Updated for latest stb-tt-rs<commit_after>// See LICENSE file for copyright and license details.

use std::path::{Path};
use std::iter::{repeat};
use std::cmp;
use std::collections::HashMap;
use stb_tt::{Font};
use cgmath::{Vector3, Vector2};
use common::types::{Size2, ZInt, ZFloat};
use common::fs;
use misc::{add_quad_to_vec};
use texture::{Texture};
use types::{VertexCoord, TextureCoord, ScreenPos};
use mesh::{Mesh};
use zgl::{Zgl};

#[derive(Clone)]
pub struct Glyph {
    pos: ScreenPos,
    size: Size2<ZInt>,
    xoff: ZInt,
    yoff: ZInt,
}

pub struct FontStash {
    size: ZFloat,
    font: Font,
    texture: Texture,
    texture_size: ZInt,
    pos: ScreenPos,
    glyphs: HashMap<char, Glyph>,
    max_h: ZInt,
}

impl FontStash {
    pub fn new(zgl: &Zgl, font_path: &Path, size: ZFloat) -> FontStash {
        let texture_size = 1024;
        let font = Font::from_reader(&mut fs::load(font_path), size);
        let texture = Texture::new_empty(
            zgl, Size2{w: texture_size, h: texture_size});
        FontStash {
            size: size,
            font: font,
            texture: texture,
            texture_size: texture_size,
            pos: ScreenPos{v: Vector2{x: 0, y: 0}},
            glyphs: HashMap::new(),
            max_h: 0,
        }
    }

    pub fn get_glyph(&mut self, zgl: &Zgl, c: char) -> Glyph {
        if let Some(r) = self.glyphs.get(&c) {
            return r.clone();
        }
        self.add_glyph(zgl, c)
    }

    pub fn get_size(&self) -> ZFloat {
        self.size
    }

    pub fn get_text_size(&mut self, zgl: &Zgl, text: &str) -> (ScreenPos, Size2<ZInt>) {
        let mut size = Size2{w: 0, h: 0};
        let mut pos = ScreenPos{v: Vector2{x: 0, y: 0}};
        for c in text.chars() {
            let glyph = self.get_glyph(zgl, c);
            let w = glyph.size.w;
            let h = glyph.size.h;
            let yoff = -glyph.yoff;
            if pos.v.y > yoff - h {
                pos.v.y = yoff - h;
            }
            if size.h < yoff {
                size.h = yoff;
            }
            size.w += w + glyph.xoff;
        }
        (pos, size)
    }

    // TODO: fix centred hack
    pub fn get_mesh(&mut self, zgl: &Zgl, text: &str, centred: bool) -> Mesh {
        let mut vertex_data = Vec::new();
        let mut tex_data = Vec::new();
        let s = self.texture_size as ZFloat;
        let mut i = if centred {
            let (_, Size2{w, h: _}) = self.get_text_size(zgl, text);
            (-w / 2) as ZFloat
        } else {
            0.0
        };
        for c in text.chars() {
            let glyph = self.get_glyph(zgl, c);
            let w = glyph.size.w as ZFloat;
            let h = glyph.size.h as ZFloat;
            let x1 = glyph.pos.v.x as ZFloat / s;
            let y1 = glyph.pos.v.y as ZFloat / s;
            let x2 = x1 + w / s;
            let y2 = y1 + h / s;
            add_quad_to_vec(
                &mut tex_data,
                TextureCoord{v: Vector2{x: x1, y: y1}},
                TextureCoord{v: Vector2{x: x1, y: y2}},
                TextureCoord{v: Vector2{x: x2, y: y2}},
                TextureCoord{v: Vector2{x: x2, y: y1}},
            );
            let yoff = -glyph.yoff as ZFloat;
            add_quad_to_vec(
                &mut vertex_data,
                VertexCoord{v: Vector3{x: i, y: yoff, z: 0.0}},
                VertexCoord{v: Vector3{x: i, y: yoff - h, z: 0.0}},
                VertexCoord{v: Vector3{x: w + i, y: yoff - h, z: 0.0}},
                VertexCoord{v: Vector3{x: w + i, y: yoff, z: 0.0}},
            );
            i += w + glyph.xoff as ZFloat;
        }
        let mut mesh = Mesh::new(zgl, vertex_data.as_slice());
        // TODO: remove 'clone()'?
        mesh.add_texture(zgl, self.texture.clone(), tex_data.as_slice());
        mesh
    }

    fn insert_image_to_cache(
        &mut self,
        zgl: &Zgl,
        pos: ScreenPos,
        size: Size2<ZInt>,
        bitmap: Vec<u8>
    ) {
        let mut data: Vec<_> = repeat(0u8)
            .take((size.w * size.h) as usize * 4).collect();
        for y in range(0, size.h) {
            for x in range(0, size.w) {
                let n = (x + y * size.w) as usize * 4;
                data[n + 0] = 255;
                data[n + 1] = 255;
                data[n + 2] = 255;
                data[n + 3] = bitmap[(x + y * size.w) as usize];
            }
        }
        self.texture.bind(zgl);
        self.texture.set_sub_image(zgl, pos.v, size, &data);
    }

    fn start_new_row(&mut self) {
        self.pos.v.y += self.max_h;
        self.pos.v.x = 0;
        self.max_h = 0;
        assert!(self.pos.v.y < self.texture_size);
    }

    fn add_glyph(&mut self, zgl: &Zgl, c: char) -> Glyph {
        assert!(self.glyphs.get(&c).is_none());
        let index = self.font.find_glyph_index(c);
        let (bitmap, w, h, xoff, yoff) = self.font.get_glyph(index);
        if self.pos.v.x + w > self.texture_size {
            self.start_new_row();
        }
        self.pos.v.y = cmp::max(h, self.pos.v.y);
        let pos = self.pos.clone();
        let size = Size2{w: w, h: h};
        if w * h != 0 {
            self.insert_image_to_cache(zgl, pos.clone(), size.clone(), bitmap);
        }
        let xoff = if c == ' ' {
            let space_width = (self.size / 3.0) as ZInt; // TODO: get from ttf
            xoff + space_width
        } else {
            xoff
        };
        self.pos.v.x += w;
        let glyph = Glyph {
            pos: pos,
            size: size,
            xoff: xoff,
            yoff: yoff,
        };
        if self.max_h < h - yoff {
            self.max_h = h - yoff;
        }
        self.glyphs.insert(c, glyph.clone());
        glyph
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>//! Macros used by iterators of slice.

// Inlining is_empty and len makes a huge performance difference
macro_rules! is_empty {
    // The way we encode the length of a ZST iterator, this works both for ZST
    // and non-ZST.
    ($self: ident) => {
        $self.ptr.as_ptr() as *const T == $self.end
    };
}

// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
macro_rules! len {
    ($self: ident) => {{
        #![allow(unused_unsafe)] // we're sometimes used within an unsafe block

        let start = $self.ptr;
        let size = size_from_ptr(start.as_ptr());
        if size == 0 {
            // This _cannot_ use `unchecked_sub` because we depend on wrapping
            // to represent the length of long ZST slice iterators.
            ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
        } else {
            // We know that `start <= end`, so can do better than `offset_from`,
            // which needs to deal in signed.  By setting appropriate flags here
            // we can tell LLVM this, which helps it remove bounds checks.
            // SAFETY: By the type invariant, `start <= end`
            let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
            // By also telling LLVM that the pointers are apart by an exact
            // multiple of the type size, it can optimize `len() == 0` down to
            // `start == end` instead of `(end - start) < size`.
            // SAFETY: By the type invariant, the pointers are aligned so the
            //         distance between them must be a multiple of pointee size
            unsafe { exact_div(diff, size) }
        }
    }};
}

// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
    (
        struct $name:ident -> $ptr:ty,
        $elem:ty,
        $raw_mut:tt,
        {$( $mut_:tt )?},
        {$($extra:tt)*}
    ) => {
        // Returns the first element and moves the start of the iterator forwards by 1.
        // Greatly improves performance compared to an inlined function. The iterator
        // must not be empty.
        macro_rules! next_unchecked {
            ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
        }

        // Returns the last element and moves the end of the iterator backwards by 1.
        // Greatly improves performance compared to an inlined function. The iterator
        // must not be empty.
        macro_rules! next_back_unchecked {
            ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
        }

        // Shrinks the iterator when T is a ZST, by moving the end of the iterator
        // backwards by `n`. `n` must not exceed `self.len()`.
        macro_rules! zst_shrink {
            ($self: ident, $n: ident) => {
                $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
            }
        }

        impl<'a, T> $name<'a, T> {
            // Helper function for creating a slice from the iterator.
            #[inline(always)]
            fn make_slice(&self) -> &'a [T] {
                // SAFETY: the iterator was created from a slice with pointer
                // `self.ptr` and length `len!(self)`. This guarantees that all
                // the prerequisites for `from_raw_parts` are fulfilled.
                unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
            }

            // Helper function for moving the start of the iterator forwards by `offset` elements,
            // returning the old start.
            // Unsafe because the offset must not exceed `self.len()`.
            #[inline(always)]
            unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
                if mem::size_of::<T>() == 0 {
                    zst_shrink!(self, offset);
                    self.ptr.as_ptr()
                } else {
                    let old = self.ptr.as_ptr();
                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
                    // so this new pointer is inside `self` and thus guaranteed to be non-null.
                    self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
                    old
                }
            }

            // Helper function for moving the end of the iterator backwards by `offset` elements,
            // returning the new end.
            // Unsafe because the offset must not exceed `self.len()`.
            #[inline(always)]
            unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
                if mem::size_of::<T>() == 0 {
                    zst_shrink!(self, offset);
                    self.ptr.as_ptr()
                } else {
                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
                    // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
                    // is in bounds of `slice`, which fulfills the other requirements for `offset`.
                    self.end = unsafe { self.end.offset(-offset) };
                    self.end
                }
            }
        }

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<T> ExactSizeIterator for $name<'_, T> {
            #[inline(always)]
            fn len(&self) -> usize {
                len!(self)
            }

            #[inline(always)]
            fn is_empty(&self) -> bool {
                is_empty!(self)
            }
        }

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, T> Iterator for $name<'a, T> {
            type Item = $elem;

            #[inline]
            fn next(&mut self) -> Option<$elem> {
                // could be implemented with slices, but this avoids bounds checks

                // SAFETY: `assume` calls are safe since a slice's start pointer
                // must be non-null, and slices over non-ZSTs must also have a
                // non-null end pointer. The call to `next_unchecked!` is safe
                // since we check if the iterator is empty first.
                unsafe {
                    assume(!self.ptr.as_ptr().is_null());
                    if mem::size_of::<T>() != 0 {
                        assume(!self.end.is_null());
                    }
                    if is_empty!(self) {
                        None
                    } else {
                        Some(next_unchecked!(self))
                    }
                }
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                let exact = len!(self);
                (exact, Some(exact))
            }

            #[inline]
            fn count(self) -> usize {
                len!(self)
            }

            #[inline]
            fn nth(&mut self, n: usize) -> Option<$elem> {
                if n >= len!(self) {
                    // This iterator is now empty.
                    if mem::size_of::<T>() == 0 {
                        // We have to do it this way as `ptr` may never be 0, but `end`
                        // could be (due to wrapping).
                        self.end = self.ptr.as_ptr();
                    } else {
                        // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
                        unsafe {
                            self.ptr = NonNull::new_unchecked(self.end as *mut T);
                        }
                    }
                    return None;
                }
                // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
                unsafe {
                    self.post_inc_start(n as isize);
                    Some(next_unchecked!(self))
                }
            }

            #[inline]
            fn advance_by(&mut self, n: usize) -> Result<(), usize>{
                let advance = cmp::min(n, len!(self));
                // SAFETY: By construction, `advance` does not exceed `self.len()`.
                unsafe { self.post_inc_start(advance as isize) };
                if advance == n { Ok(()) } else { Err(advance) }
            }

            #[inline]
            fn last(mut self) -> Option<$elem> {
                self.next_back()
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn for_each<F>(mut self, mut f: F)
            where
                Self: Sized,
                F: FnMut(Self::Item),
            {
                while let Some(x) = self.next() {
                    f(x);
                }
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn all<F>(&mut self, mut f: F) -> bool
            where
                Self: Sized,
                F: FnMut(Self::Item) -> bool,
            {
                while let Some(x) = self.next() {
                    if !f(x) {
                        return false;
                    }
                }
                true
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn any<F>(&mut self, mut f: F) -> bool
            where
                Self: Sized,
                F: FnMut(Self::Item) -> bool,
            {
                while let Some(x) = self.next() {
                    if f(x) {
                        return true;
                    }
                }
                false
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
            where
                Self: Sized,
                P: FnMut(&Self::Item) -> bool,
            {
                while let Some(x) = self.next() {
                    if predicate(&x) {
                        return Some(x);
                    }
                }
                None
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
            where
                Self: Sized,
                F: FnMut(Self::Item) -> Option<B>,
            {
                while let Some(x) = self.next() {
                    if let Some(y) = f(x) {
                        return Some(y);
                    }
                }
                None
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile. Also, the `assume` avoids a bounds check.
            #[inline]
            #[rustc_inherit_overflow_checks]
            fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
                Self: Sized,
                P: FnMut(Self::Item) -> bool,
            {
                let n = len!(self);
                let mut i = 0;
                while let Some(x) = self.next() {
                    if predicate(x) {
                        // SAFETY: we are guaranteed to be in bounds by the loop invariant:
                        // when `i >= n`, `self.next()` returns `None` and the loop breaks.
                        unsafe { assume(i < n) };
                        return Some(i);
                    }
                    i += 1;
                }
                None
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile. Also, the `assume` avoids a bounds check.
            #[inline]
            fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
                P: FnMut(Self::Item) -> bool,
                Self: Sized + ExactSizeIterator + DoubleEndedIterator
            {
                let n = len!(self);
                let mut i = n;
                while let Some(x) = self.next_back() {
                    i -= 1;
                    if predicate(x) {
                        // SAFETY: `i` must be lower than `n` since it starts at `n`
                        // and is only decreasing.
                        unsafe { assume(i < n) };
                        return Some(i);
                    }
                }
                None
            }

            #[doc(hidden)]
            unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
                // SAFETY: the caller must guarantee that `i` is in bounds of
                // the underlying slice, so `i` cannot overflow an `isize`, and
                // the returned references is guaranteed to refer to an element
                // of the slice and thus guaranteed to be valid.
                //
                // Also note that the caller also guarantees that we're never
                // called with the same index again, and that no other methods
                // that will access this subslice are called, so it is valid
                // for the returned reference to be mutable in the case of
                // `IterMut`
                unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
            }

            $($extra)*
        }

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, T> DoubleEndedIterator for $name<'a, T> {
            #[inline]
            fn next_back(&mut self) -> Option<$elem> {
                // could be implemented with slices, but this avoids bounds checks

                // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
                // and slices over non-ZSTs must also have a non-null end pointer.
                // The call to `next_back_unchecked!` is safe since we check if the iterator is
                // empty first.
                unsafe {
                    assume(!self.ptr.as_ptr().is_null());
                    if mem::size_of::<T>() != 0 {
                        assume(!self.end.is_null());
                    }
                    if is_empty!(self) {
                        None
                    } else {
                        Some(next_back_unchecked!(self))
                    }
                }
            }

            #[inline]
            fn nth_back(&mut self, n: usize) -> Option<$elem> {
                if n >= len!(self) {
                    // This iterator is now empty.
                    self.end = self.ptr.as_ptr();
                    return None;
                }
                // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
                unsafe {
                    self.pre_dec_end(n as isize);
                    Some(next_back_unchecked!(self))
                }
            }

            #[inline]
            fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
                let advance = cmp::min(n, len!(self));
                // SAFETY: By construction, `advance` does not exceed `self.len()`.
                unsafe { self.pre_dec_end(advance as isize) };
                if advance == n { Ok(()) } else { Err(advance) }
            }
        }

        #[stable(feature = "fused", since = "1.26.0")]
        impl<T> FusedIterator for $name<'_, T> {}

        #[unstable(feature = "trusted_len", issue = "37572")]
        unsafe impl<T> TrustedLen for $name<'_, T> {}
    }
}

macro_rules! forward_iterator {
    ($name:ident: $elem:ident, $iter_of:ty) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
        where
            P: FnMut(&T) -> bool,
        {
            type Item = $iter_of;

            #[inline]
            fn next(&mut self) -> Option<$iter_of> {
                self.inner.next()
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.inner.size_hint()
            }
        }

        #[stable(feature = "fused", since = "1.26.0")]
        impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
    };
}
<commit_msg>Fix whitespace<commit_after>//! Macros used by iterators of slice.

// Inlining is_empty and len makes a huge performance difference
macro_rules! is_empty {
    // The way we encode the length of a ZST iterator, this works both for ZST
    // and non-ZST.
    ($self: ident) => {
        $self.ptr.as_ptr() as *const T == $self.end
    };
}

// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
macro_rules! len {
    ($self: ident) => {{
        #![allow(unused_unsafe)] // we're sometimes used within an unsafe block

        let start = $self.ptr;
        let size = size_from_ptr(start.as_ptr());
        if size == 0 {
            // This _cannot_ use `unchecked_sub` because we depend on wrapping
            // to represent the length of long ZST slice iterators.
            ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
        } else {
            // We know that `start <= end`, so can do better than `offset_from`,
            // which needs to deal in signed.  By setting appropriate flags here
            // we can tell LLVM this, which helps it remove bounds checks.
            // SAFETY: By the type invariant, `start <= end`
            let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
            // By also telling LLVM that the pointers are apart by an exact
            // multiple of the type size, it can optimize `len() == 0` down to
            // `start == end` instead of `(end - start) < size`.
            // SAFETY: By the type invariant, the pointers are aligned so the
            //         distance between them must be a multiple of pointee size
            unsafe { exact_div(diff, size) }
        }
    }};
}

// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
    (
        struct $name:ident -> $ptr:ty,
        $elem:ty,
        $raw_mut:tt,
        {$( $mut_:tt )?},
        {$($extra:tt)*}
    ) => {
        // Returns the first element and moves the start of the iterator forwards by 1.
        // Greatly improves performance compared to an inlined function. The iterator
        // must not be empty.
        macro_rules! next_unchecked {
            ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
        }

        // Returns the last element and moves the end of the iterator backwards by 1.
        // Greatly improves performance compared to an inlined function. The iterator
        // must not be empty.
        macro_rules! next_back_unchecked {
            ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
        }

        // Shrinks the iterator when T is a ZST, by moving the end of the iterator
        // backwards by `n`. `n` must not exceed `self.len()`.
        macro_rules! zst_shrink {
            ($self: ident, $n: ident) => {
                $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
            }
        }

        impl<'a, T> $name<'a, T> {
            // Helper function for creating a slice from the iterator.
            #[inline(always)]
            fn make_slice(&self) -> &'a [T] {
                // SAFETY: the iterator was created from a slice with pointer
                // `self.ptr` and length `len!(self)`. This guarantees that all
                // the prerequisites for `from_raw_parts` are fulfilled.
                unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
            }

            // Helper function for moving the start of the iterator forwards by `offset` elements,
            // returning the old start.
            // Unsafe because the offset must not exceed `self.len()`.
            #[inline(always)]
            unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
                if mem::size_of::<T>() == 0 {
                    zst_shrink!(self, offset);
                    self.ptr.as_ptr()
                } else {
                    let old = self.ptr.as_ptr();
                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
                    // so this new pointer is inside `self` and thus guaranteed to be non-null.
                    self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
                    old
                }
            }

            // Helper function for moving the end of the iterator backwards by `offset` elements,
            // returning the new end.
            // Unsafe because the offset must not exceed `self.len()`.
            #[inline(always)]
            unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
                if mem::size_of::<T>() == 0 {
                    zst_shrink!(self, offset);
                    self.ptr.as_ptr()
                } else {
                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
                    // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
                    // is in bounds of `slice`, which fulfills the other requirements for `offset`.
                    self.end = unsafe { self.end.offset(-offset) };
                    self.end
                }
            }
        }

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<T> ExactSizeIterator for $name<'_, T> {
            #[inline(always)]
            fn len(&self) -> usize {
                len!(self)
            }

            #[inline(always)]
            fn is_empty(&self) -> bool {
                is_empty!(self)
            }
        }

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, T> Iterator for $name<'a, T> {
            type Item = $elem;

            #[inline]
            fn next(&mut self) -> Option<$elem> {
                // could be implemented with slices, but this avoids bounds checks

                // SAFETY: `assume` calls are safe since a slice's start pointer
                // must be non-null, and slices over non-ZSTs must also have a
                // non-null end pointer. The call to `next_unchecked!` is safe
                // since we check if the iterator is empty first.
                unsafe {
                    assume(!self.ptr.as_ptr().is_null());
                    if mem::size_of::<T>() != 0 {
                        assume(!self.end.is_null());
                    }
                    if is_empty!(self) {
                        None
                    } else {
                        Some(next_unchecked!(self))
                    }
                }
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                let exact = len!(self);
                (exact, Some(exact))
            }

            #[inline]
            fn count(self) -> usize {
                len!(self)
            }

            #[inline]
            fn nth(&mut self, n: usize) -> Option<$elem> {
                if n >= len!(self) {
                    // This iterator is now empty.
                    if mem::size_of::<T>() == 0 {
                        // We have to do it this way as `ptr` may never be 0, but `end`
                        // could be (due to wrapping).
                        self.end = self.ptr.as_ptr();
                    } else {
                        // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
                        unsafe {
                            self.ptr = NonNull::new_unchecked(self.end as *mut T);
                        }
                    }
                    return None;
                }
                // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
                unsafe {
                    self.post_inc_start(n as isize);
                    Some(next_unchecked!(self))
                }
            }

            fn advance_by(&mut self, n: usize) -> Result<(), usize> {
                let advance = cmp::min(n, len!(self));
                // SAFETY: By construction, `advance` does not exceed `self.len()`.
                unsafe { self.post_inc_start(advance as isize) };
                if advance == n { Ok(()) } else { Err(advance) }
            }

            #[inline]
            fn last(mut self) -> Option<$elem> {
                self.next_back()
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn for_each<F>(mut self, mut f: F)
            where
                Self: Sized,
                F: FnMut(Self::Item),
            {
                while let Some(x) = self.next() {
                    f(x);
                }
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn all<F>(&mut self, mut f: F) -> bool
            where
                Self: Sized,
                F: FnMut(Self::Item) -> bool,
            {
                while let Some(x) = self.next() {
                    if !f(x) {
                        return false;
                    }
                }
                true
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn any<F>(&mut self, mut f: F) -> bool
            where
                Self: Sized,
                F: FnMut(Self::Item) -> bool,
            {
                while let Some(x) = self.next() {
                    if f(x) {
                        return true;
                    }
                }
                false
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
            where
                Self: Sized,
                P: FnMut(&Self::Item) -> bool,
            {
                while let Some(x) = self.next() {
                    if predicate(&x) {
                        return Some(x);
                    }
                }
                None
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile.
            #[inline]
            fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
            where
                Self: Sized,
                F: FnMut(Self::Item) -> Option<B>,
            {
                while let Some(x) = self.next() {
                    if let Some(y) = f(x) {
                        return Some(y);
                    }
                }
                None
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile. Also, the `assume` avoids a bounds check.
            #[inline]
            #[rustc_inherit_overflow_checks]
            fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
                Self: Sized,
                P: FnMut(Self::Item) -> bool,
            {
                let n = len!(self);
                let mut i = 0;
                while let Some(x) = self.next() {
                    if predicate(x) {
                        // SAFETY: we are guaranteed to be in bounds by the loop invariant:
                        // when `i >= n`, `self.next()` returns `None` and the loop breaks.
                        unsafe { assume(i < n) };
                        return Some(i);
                    }
                    i += 1;
                }
                None
            }

            // We override the default implementation, which uses `try_fold`,
            // because this simple implementation generates less LLVM IR and is
            // faster to compile. Also, the `assume` avoids a bounds check.
            #[inline]
            fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
                P: FnMut(Self::Item) -> bool,
                Self: Sized + ExactSizeIterator + DoubleEndedIterator
            {
                let n = len!(self);
                let mut i = n;
                while let Some(x) = self.next_back() {
                    i -= 1;
                    if predicate(x) {
                        // SAFETY: `i` must be lower than `n` since it starts at `n`
                        // and is only decreasing.
                        unsafe { assume(i < n) };
                        return Some(i);
                    }
                }
                None
            }

            #[doc(hidden)]
            unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
                // SAFETY: the caller must guarantee that `i` is in bounds of
                // the underlying slice, so `i` cannot overflow an `isize`, and
                // the returned references is guaranteed to refer to an element
                // of the slice and thus guaranteed to be valid.
                //
                // Also note that the caller also guarantees that we're never
                // called with the same index again, and that no other methods
                // that will access this subslice are called, so it is valid
                // for the returned reference to be mutable in the case of
                // `IterMut`
                unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
            }

            $($extra)*
        }

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, T> DoubleEndedIterator for $name<'a, T> {
            #[inline]
            fn next_back(&mut self) -> Option<$elem> {
                // could be implemented with slices, but this avoids bounds checks

                // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
                // and slices over non-ZSTs must also have a non-null end pointer.
                // The call to `next_back_unchecked!` is safe since we check if the iterator is
                // empty first.
                unsafe {
                    assume(!self.ptr.as_ptr().is_null());
                    if mem::size_of::<T>() != 0 {
                        assume(!self.end.is_null());
                    }
                    if is_empty!(self) {
                        None
                    } else {
                        Some(next_back_unchecked!(self))
                    }
                }
            }

            #[inline]
            fn nth_back(&mut self, n: usize) -> Option<$elem> {
                if n >= len!(self) {
                    // This iterator is now empty.
                    self.end = self.ptr.as_ptr();
                    return None;
                }
                // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
                unsafe {
                    self.pre_dec_end(n as isize);
                    Some(next_back_unchecked!(self))
                }
            }

            #[inline]
            fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
                let advance = cmp::min(n, len!(self));
                // SAFETY: By construction, `advance` does not exceed `self.len()`.
                unsafe { self.pre_dec_end(advance as isize) };
                if advance == n { Ok(()) } else { Err(advance) }
            }
        }

        #[stable(feature = "fused", since = "1.26.0")]
        impl<T> FusedIterator for $name<'_, T> {}

        #[unstable(feature = "trusted_len", issue = "37572")]
        unsafe impl<T> TrustedLen for $name<'_, T> {}
    }
}

macro_rules! forward_iterator {
    ($name:ident: $elem:ident, $iter_of:ty) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
        where
            P: FnMut(&T) -> bool,
        {
            type Item = $iter_of;

            #[inline]
            fn next(&mut self) -> Option<$iter_of> {
                self.inner.next()
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.inner.size_hint()
            }
        }

        #[stable(feature = "fused", since = "1.26.0")]
        impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
    };
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use crate::{db::RootDatabase, FilePosition};
use hir::db::AstDatabase;
use ra_db::SourceDatabase;
use rustc_hash::FxHashMap;

use ra_syntax::{
    algo::{find_node_at_offset, replace_descendants},
    ast::{self},
    AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T,
};

pub struct ExpandedMacro {
    pub name: String,
    pub expansion: String,
}

pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
    let parse = db.parse(position.file_id);
    let file = parse.tree();
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
    let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;

    let source = hir::Source::new(position.file_id.into(), mac.syntax());
    let expanded = expand_macro_recur(db, source, &mac)?;

    // FIXME:
    // macro expansion may lose all white space information
    // But we hope someday we can use ra_fmt for that
    let expansion = insert_whitespaces(expanded);
    Some(ExpandedMacro { name: name_ref.text().to_string(), expansion })
}

fn expand_macro_recur(
    db: &RootDatabase,
    source: hir::Source<&SyntaxNode>,
    macro_call: &ast::MacroCall,
) -> Option<SyntaxNode> {
    let analyzer = hir::SourceAnalyzer::new(db, source, None);
    let expansion = analyzer.expand(db, &macro_call)?;
    let macro_file_id = expansion.file_id();
    let expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?;

    let children = expanded.descendants().filter_map(ast::MacroCall::cast);
    let mut replaces = FxHashMap::default();

    for child in children.into_iter() {
        let source = hir::Source::new(macro_file_id, source.ast);
        let new_node = expand_macro_recur(db, source, &child)?;

        replaces.insert(child.syntax().clone().into(), new_node.into());
    }

    Some(replace_descendants(&expanded, &replaces))
}

// FIXME: It would also be cool to share logic here and in the mbe tests,
// which are pretty unreadable at the moment.
fn insert_whitespaces(syn: SyntaxNode) -> String {
    use SyntaxKind::*;

    let mut res = String::new();
    let mut token_iter = syn
        .preorder_with_tokens()
        .filter_map(|event| {
            if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
                Some(token)
            } else {
                None
            }
        })
        .peekable();

    let mut indent = 0;
    let mut last: Option<SyntaxKind> = None;

    while let Some(token) = token_iter.next() {
        let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
            token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
        };
        let is_last = |f: fn(SyntaxKind) -> bool, default| -> bool {
            last.map(|it| f(it)).unwrap_or(default)
        };

        res += &match token.kind() {
            k @ _
                if (k.is_keyword() || k.is_literal() || k == IDENT)
                    && is_next(|it| !it.is_punct(), true) =>
            {
                token.text().to_string() + " "
            }
            L_CURLY if is_next(|it| it != R_CURLY, true) => {
                indent += 1;
                format!(" {{\n{}", "  ".repeat(indent))
            }
            R_CURLY if is_last(|it| it != L_CURLY, true) => {
                indent = indent.checked_sub(1).unwrap_or(0);
                format!("\n}}{}", "  ".repeat(indent))
            }
            R_CURLY => {
                indent = indent.checked_sub(1).unwrap_or(0);
                format!("}}\n{}", "  ".repeat(indent))
            }
            T![;] => format!(";\n{}", "  ".repeat(indent)),
            T![->] => " -> ".to_string(),
            T![=] => " = ".to_string(),
            T![=>] => " => ".to_string(),
            _ => token.text().to_string(),
        };

        last = Some(token.kind());
    }

    res
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::mock_analysis::analysis_and_position;
    use insta::assert_snapshot;

    fn check_expand_macro(fixture: &str) -> ExpandedMacro {
        let (analysis, pos) = analysis_and_position(fixture);
        analysis.expand_macro(pos).unwrap().unwrap()
    }

    #[test]
    fn macro_expand_recursive_expansion() {
        let res = check_expand_macro(
            r#"
        //- /lib.rs
        macro_rules! bar {
            () => { fn  b() {} }
        }
        macro_rules! foo {
            () => { bar!(); }
        }
        macro_rules! baz {
            () => { foo!(); }
        }
        f<|>oo!();
        "#,
        );

        assert_eq!(res.name, "foo");
        assert_snapshot!(res.expansion, @r###"
fn b(){}
"###);
    }

    #[test]
    fn macro_expand_multiple_lines() {
        let res = check_expand_macro(
            r#"
        //- /lib.rs
        macro_rules! foo {
            () => {
                fn some_thing() -> u32 {
                    let a = 0;
                    a + 10
                }
            }
        }
        f<|>oo!();
        "#,
        );

        assert_eq!(res.name, "foo");
        assert_snapshot!(res.expansion, @r###"
fn some_thing() -> u32 {
  let a = 0;
  a+10
}
"###);
    }
}
<commit_msg>Add shot doc for expand_macro module<commit_after>//! This modules implements "expand macro" functionality in the IDE

use crate::{db::RootDatabase, FilePosition};
use hir::db::AstDatabase;
use ra_db::SourceDatabase;
use rustc_hash::FxHashMap;

use ra_syntax::{
    algo::{find_node_at_offset, replace_descendants},
    ast::{self},
    AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T,
};

pub struct ExpandedMacro {
    pub name: String,
    pub expansion: String,
}

pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
    let parse = db.parse(position.file_id);
    let file = parse.tree();
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
    let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;

    let source = hir::Source::new(position.file_id.into(), mac.syntax());
    let expanded = expand_macro_recur(db, source, &mac)?;

    // FIXME:
    // macro expansion may lose all white space information
    // But we hope someday we can use ra_fmt for that
    let expansion = insert_whitespaces(expanded);
    Some(ExpandedMacro { name: name_ref.text().to_string(), expansion })
}

fn expand_macro_recur(
    db: &RootDatabase,
    source: hir::Source<&SyntaxNode>,
    macro_call: &ast::MacroCall,
) -> Option<SyntaxNode> {
    let analyzer = hir::SourceAnalyzer::new(db, source, None);
    let expansion = analyzer.expand(db, &macro_call)?;
    let macro_file_id = expansion.file_id();
    let expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?;

    let children = expanded.descendants().filter_map(ast::MacroCall::cast);
    let mut replaces = FxHashMap::default();

    for child in children.into_iter() {
        let source = hir::Source::new(macro_file_id, source.ast);
        let new_node = expand_macro_recur(db, source, &child)?;

        replaces.insert(child.syntax().clone().into(), new_node.into());
    }

    Some(replace_descendants(&expanded, &replaces))
}

// FIXME: It would also be cool to share logic here and in the mbe tests,
// which are pretty unreadable at the moment.
fn insert_whitespaces(syn: SyntaxNode) -> String {
    use SyntaxKind::*;

    let mut res = String::new();
    let mut token_iter = syn
        .preorder_with_tokens()
        .filter_map(|event| {
            if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
                Some(token)
            } else {
                None
            }
        })
        .peekable();

    let mut indent = 0;
    let mut last: Option<SyntaxKind> = None;

    while let Some(token) = token_iter.next() {
        let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
            token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
        };
        let is_last = |f: fn(SyntaxKind) -> bool, default| -> bool {
            last.map(|it| f(it)).unwrap_or(default)
        };

        res += &match token.kind() {
            k @ _
                if (k.is_keyword() || k.is_literal() || k == IDENT)
                    && is_next(|it| !it.is_punct(), true) =>
            {
                token.text().to_string() + " "
            }
            L_CURLY if is_next(|it| it != R_CURLY, true) => {
                indent += 1;
                format!(" {{\n{}", "  ".repeat(indent))
            }
            R_CURLY if is_last(|it| it != L_CURLY, true) => {
                indent = indent.checked_sub(1).unwrap_or(0);
                format!("\n}}{}", "  ".repeat(indent))
            }
            R_CURLY => {
                indent = indent.checked_sub(1).unwrap_or(0);
                format!("}}\n{}", "  ".repeat(indent))
            }
            T![;] => format!(";\n{}", "  ".repeat(indent)),
            T![->] => " -> ".to_string(),
            T![=] => " = ".to_string(),
            T![=>] => " => ".to_string(),
            _ => token.text().to_string(),
        };

        last = Some(token.kind());
    }

    res
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::mock_analysis::analysis_and_position;
    use insta::assert_snapshot;

    fn check_expand_macro(fixture: &str) -> ExpandedMacro {
        let (analysis, pos) = analysis_and_position(fixture);
        analysis.expand_macro(pos).unwrap().unwrap()
    }

    #[test]
    fn macro_expand_recursive_expansion() {
        let res = check_expand_macro(
            r#"
        //- /lib.rs
        macro_rules! bar {
            () => { fn  b() {} }
        }
        macro_rules! foo {
            () => { bar!(); }
        }
        macro_rules! baz {
            () => { foo!(); }
        }
        f<|>oo!();
        "#,
        );

        assert_eq!(res.name, "foo");
        assert_snapshot!(res.expansion, @r###"
fn b(){}
"###);
    }

    #[test]
    fn macro_expand_multiple_lines() {
        let res = check_expand_macro(
            r#"
        //- /lib.rs
        macro_rules! foo {
            () => {
                fn some_thing() -> u32 {
                    let a = 0;
                    a + 10
                }
            }
        }
        f<|>oo!();
        "#,
        );

        assert_eq!(res.name, "foo");
        assert_snapshot!(res.expansion, @r###"
fn some_thing() -> u32 {
  let a = 0;
  a+10
}
"###);
    }
}
<|endoftext|>