<commit_before>use std::{
    io::{self, Error, ErrorKind},
    mem,
    net::SocketAddr,
    os::unix::io::AsRawFd,
    ptr,
    task::{Context, Poll},
};

use async_trait::async_trait;
use futures::{future::poll_fn, ready};
use mio::net::UdpSocket;
use socket2::{Domain, Protocol, SockAddr, Socket, Type};

use crate::{
    config::RedirType,
    relay::{redir::UdpSocketRedirExt, sys::sockaddr_to_std},
};

pub fn check_support_tproxy() -> io::Result<()> {
    Ok(())
}

pub struct UdpRedirSocket {
    io: PollEvented<mio::net::UdpSocket>,
}

impl UdpRedirSocket {
    /// Create a new UDP socket binded to `addr`
    ///
    /// This will allow binding to `addr` that is not in local host
    pub fn bind(ty: RedirType, addr: &SocketAddr) -> io::Result<UdpRedirSocket> {
        if ty != RedirType::TProxy {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "not supported udp transparent proxy type",
            ));
        }

        let domain = match *addr {
            SocketAddr::V4(..) => Domain::ipv4(),
            SocketAddr::V6(..) => Domain::ipv6(),
        };
        let socket = Socket::new(domain, Type::dgram(), Some(Protocol::udp()))?;
        set_socket_before_bind(addr, &socket)?;

        socket.set_nonblocking(true)?;
        socket.set_reuse_address(true)?;

        socket.bind(&SockAddr::from(*addr))?;

        let msock = mio::net::UdpSocket::from_socket(socket.into_udp_socket())?;
        let io = PollEvented::new(msock)?;
        Ok(UdpRedirSocket { io })
    }

    /// Send data to the socket to the given target address
    pub async fn send_to(&mut self, buf: &[u8], target: &SocketAddr) -> io::Result<usize> {
        poll_fn(|cx| self.poll_send_to(cx, buf, target)).await
    }

    fn poll_send_to(&self, cx: &mut Context<'_>, buf: &[u8], target: &SocketAddr) -> Poll<io::Result<usize>> {
        ready!(self.io.poll_write_ready(cx))?;

        match self.io.get_ref().send_to(buf, target) {
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                self.io.clear_write_ready(cx)?;
                Poll::Pending
            }
            x => Poll::Ready(x),
        }
    }

    /// Returns the local address that this socket is bound to.
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.io.get_ref().local_addr()
    }

    fn poll_recv_from(
        &self,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<(usize, SocketAddr, SocketAddr)>> {
        ready!(self.io.poll_read_ready(cx, mio::Ready::readable()))?;

        match recv_from_with_destination(self.io.get_ref(), buf) {
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                self.io.clear_read_ready(cx, mio::Ready::readable())?;
                Poll::Pending
            }
            x => Poll::Ready(x),
        }
    }
}

#[async_trait]
impl UdpSocketRedirExt for UdpRedirSocket {
    async fn recv_from_redir(&mut self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {
        poll_fn(|cx| self.poll_recv_from(cx, buf)).await
    }
}

fn set_bindany(level: libc::c_int, socket: &Socket) -> io::Result<()> {
    let fd = socket.as_raw_fd();

    let enable: libc::c_int = 1;

    // https://www.freebsd.org/cgi/man.cgi?query=ip&sektion=4&manpath=FreeBSD+9.0-RELEASE
    let ret = libc::setsockopt(
        fd,
        level,
        libc::IP_BINDANY,
        &enable as *const _ as *const _,
        mem::size_of_val(&enable) as libc::socklen_t,
    );
    if ret != 0 {
        return Err(Error::last_os_error());
    }

    Ok(())
}

fn set_socket_before_bind(addr: &SocketAddr, socket: &Socket) -> io::Result<()> {
    let fd = socket.as_raw_fd();

    let enable: libc::c_int = 1;

    unsafe {
        // https://www.freebsd.org/cgi/man.cgi?query=ip&sektion=4&manpath=FreeBSD+9.0-RELEASE
        let (level, opt) = match *addr {
            SocketAddr::V4(..) => (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR),
            SocketAddr::V6(..) => (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR),
        };

        // 1. BINDANY
        set_bindany(level, socket)?;

        // 2. set ORIGDSTADDR for retrieving original destination address
        let ret = libc::setsockopt(
            fd,
            level,
            opt,
            &enable as *const _ as *const _,
            mem::size_of_val(&enable) as libc::socklen_t,
        );
        if ret != 0 {
            return Err(Error::last_os_error());
        }
    }

    Ok(())
}

fn get_destination_addr(msg: &libc::msghdr) -> Option<libc::sockaddr_storage> {
    // https://www.freebsd.org/cgi/man.cgi?ip(4)
    //
    // Called `recvmsg` with `IP_ORIGDSTADDR` set

    unsafe {
        let mut cmsg: *mut libc::cmsghdr = libc::CMSG_FIRSTHDR(msg);
        while !cmsg.is_null() {
            let rcmsg = &*cmsg;
            match (rcmsg.cmsg_level, rcmsg.cmsg_type) {
                (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
                    let mut dst_addr: libc::sockaddr_storage = mem::zeroed();

                    ptr::copy(
                        libc::CMSG_DATA(cmsg),
                        &mut dst_addr as *mut _ as *mut _,
                        mem::size_of::<libc::sockaddr_in>(),
                    );

                    return Some(dst_addr);
                }
                (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
                    let mut dst_addr: libc::sockaddr_storage = mem::zeroed();

                    ptr::copy(
                        libc::CMSG_DATA(cmsg),
                        &mut dst_addr as *mut _ as *mut _,
                        mem::size_of::<libc::sockaddr_in6>(),
                    );

                    return Some(dst_addr);
                }
                _ => {}
            }
            cmsg = libc::CMSG_NXTHDR(msg, cmsg);
        }
    }

    None
}

fn recv_from_with_destination(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {
    unsafe {
        let mut control_buf = [0u8; 64];
        let mut src_addr: libc::sockaddr_storage = mem::zeroed();

        let mut msg: libc::msghdr = mem::zeroed();
        msg.msg_name = &mut src_addr as *mut _ as *mut _;
        msg.msg_namelen = mem::size_of_val(&src_addr) as libc::socklen_t;

        let mut iov = libc::iovec {
            iov_base: buf.as_mut_ptr() as *mut _,
            iov_len: buf.len() as libc::size_t,
        };
        msg.msg_iov = &mut iov;
        msg.msg_iovlen = 1;

        msg.msg_control = control_buf.as_mut_ptr() as *mut _;
        msg.msg_controllen = control_buf.len() as libc::size_t;

        let fd = socket.as_raw_fd();
        let ret = libc::recvmsg(fd, &mut msg, 0);
        if ret < 0 {
            return Err(Error::last_os_error());
        }

        let dst_addr = match get_destination_addr(&msg) {
            None => {
                let err = Error::new(ErrorKind::InvalidData, "missing destination address in msghdr");
                return Err(err);
            }
            Some(d) => d,
        };

        Ok((ret as usize, sockaddr_to_std(&src_addr)?, sockaddr_to_std(&dst_addr)?))
    }
}
<commit_msg>OpenBSD uses SO_BINDANY<commit_after>use std::{
    io::{self, Error, ErrorKind},
    mem,
    net::SocketAddr,
    os::unix::io::AsRawFd,
    ptr,
    task::{Context, Poll},
};

use async_trait::async_trait;
use futures::{future::poll_fn, ready};
use mio::net::UdpSocket;
use socket2::{Domain, Protocol, SockAddr, Socket, Type};

use crate::{
    config::RedirType,
    relay::{redir::UdpSocketRedirExt, sys::sockaddr_to_std},
};

pub fn check_support_tproxy() -> io::Result<()> {
    Ok(())
}

pub struct UdpRedirSocket {
    io: PollEvented<mio::net::UdpSocket>,
}

impl UdpRedirSocket {
    /// Create a new UDP socket binded to `addr`
    ///
    /// This will allow binding to `addr` that is not in local host
    pub fn bind(ty: RedirType, addr: &SocketAddr) -> io::Result<UdpRedirSocket> {
        if ty != RedirType::TProxy {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "not supported udp transparent proxy type",
            ));
        }

        let domain = match *addr {
            SocketAddr::V4(..) => Domain::ipv4(),
            SocketAddr::V6(..) => Domain::ipv6(),
        };
        let socket = Socket::new(domain, Type::dgram(), Some(Protocol::udp()))?;
        set_socket_before_bind(addr, &socket)?;

        socket.set_nonblocking(true)?;
        socket.set_reuse_address(true)?;

        socket.bind(&SockAddr::from(*addr))?;

        let msock = mio::net::UdpSocket::from_socket(socket.into_udp_socket())?;
        let io = PollEvented::new(msock)?;
        Ok(UdpRedirSocket { io })
    }

    /// Send data to the socket to the given target address
    pub async fn send_to(&mut self, buf: &[u8], target: &SocketAddr) -> io::Result<usize> {
        poll_fn(|cx| self.poll_send_to(cx, buf, target)).await
    }

    fn poll_send_to(&self, cx: &mut Context<'_>, buf: &[u8], target: &SocketAddr) -> Poll<io::Result<usize>> {
        ready!(self.io.poll_write_ready(cx))?;

        match self.io.get_ref().send_to(buf, target) {
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                self.io.clear_write_ready(cx)?;
                Poll::Pending
            }
            x => Poll::Ready(x),
        }
    }

    /// Returns the local address that this socket is bound to.
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.io.get_ref().local_addr()
    }

    fn poll_recv_from(
        &self,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<(usize, SocketAddr, SocketAddr)>> {
        ready!(self.io.poll_read_ready(cx, mio::Ready::readable()))?;

        match recv_from_with_destination(self.io.get_ref(), buf) {
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                self.io.clear_read_ready(cx, mio::Ready::readable())?;
                Poll::Pending
            }
            x => Poll::Ready(x),
        }
    }
}

#[async_trait]
impl UdpSocketRedirExt for UdpRedirSocket {
    async fn recv_from_redir(&mut self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {
        poll_fn(|cx| self.poll_recv_from(cx, buf)).await
    }
}

#[cfg(target_os = "freebsd")]
fn set_bindany(level: libc::c_int, socket: &Socket) -> io::Result<()> {
    let fd = socket.as_raw_fd();

    let enable: libc::c_int = 1;

    // https://www.freebsd.org/cgi/man.cgi?query=ip&sektion=4&manpath=FreeBSD+9.0-RELEASE
    let ret = libc::setsockopt(
        fd,
        level,
        libc::IP_BINDANY,
        &enable as *const _ as *const _,
        mem::size_of_val(&enable) as libc::socklen_t,
    );
    if ret != 0 {
        return Err(Error::last_os_error());
    }

    Ok(())
}

#[cfg(target_os = "openbsd")]
fn set_bindany(level: libc::c_int, socket: &Socket) -> io::Result<()> {
    let fd = socket.as_raw_fd();

    let enable: libc::c_int = 1;

    // https://man.openbsd.org/getsockopt.2
    let ret = libc::setsockopt(
        fd,
        level,
        libc::SO_BINDANY,
        &enable as *const _ as *const _,
        mem::size_of_val(&enable) as libc::socklen_t,
    );
    if ret != 0 {
        return Err(Error::last_os_error());
    }

    Ok(())
}

fn set_socket_before_bind(addr: &SocketAddr, socket: &Socket) -> io::Result<()> {
    let fd = socket.as_raw_fd();

    let enable: libc::c_int = 1;

    unsafe {
        // https://www.freebsd.org/cgi/man.cgi?query=ip&sektion=4&manpath=FreeBSD+9.0-RELEASE
        let (level, opt) = match *addr {
            SocketAddr::V4(..) => (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR),
            SocketAddr::V6(..) => (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR),
        };

        // 1. BINDANY
        set_bindany(level, socket)?;

        // 2. set ORIGDSTADDR for retrieving original destination address
        let ret = libc::setsockopt(
            fd,
            level,
            opt,
            &enable as *const _ as *const _,
            mem::size_of_val(&enable) as libc::socklen_t,
        );
        if ret != 0 {
            return Err(Error::last_os_error());
        }
    }

    Ok(())
}

fn get_destination_addr(msg: &libc::msghdr) -> Option<libc::sockaddr_storage> {
    // https://www.freebsd.org/cgi/man.cgi?ip(4)
    //
    // Called `recvmsg` with `IP_ORIGDSTADDR` set

    unsafe {
        let mut cmsg: *mut libc::cmsghdr = libc::CMSG_FIRSTHDR(msg);
        while !cmsg.is_null() {
            let rcmsg = &*cmsg;
            match (rcmsg.cmsg_level, rcmsg.cmsg_type) {
                (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
                    let mut dst_addr: libc::sockaddr_storage = mem::zeroed();

                    ptr::copy(
                        libc::CMSG_DATA(cmsg),
                        &mut dst_addr as *mut _ as *mut _,
                        mem::size_of::<libc::sockaddr_in>(),
                    );

                    return Some(dst_addr);
                }
                (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
                    let mut dst_addr: libc::sockaddr_storage = mem::zeroed();

                    ptr::copy(
                        libc::CMSG_DATA(cmsg),
                        &mut dst_addr as *mut _ as *mut _,
                        mem::size_of::<libc::sockaddr_in6>(),
                    );

                    return Some(dst_addr);
                }
                _ => {}
            }
            cmsg = libc::CMSG_NXTHDR(msg, cmsg);
        }
    }

    None
}

fn recv_from_with_destination(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {
    unsafe {
        let mut control_buf = [0u8; 64];
        let mut src_addr: libc::sockaddr_storage = mem::zeroed();

        let mut msg: libc::msghdr = mem::zeroed();
        msg.msg_name = &mut src_addr as *mut _ as *mut _;
        msg.msg_namelen = mem::size_of_val(&src_addr) as libc::socklen_t;

        let mut iov = libc::iovec {
            iov_base: buf.as_mut_ptr() as *mut _,
            iov_len: buf.len() as libc::size_t,
        };
        msg.msg_iov = &mut iov;
        msg.msg_iovlen = 1;

        msg.msg_control = control_buf.as_mut_ptr() as *mut _;
        msg.msg_controllen = control_buf.len() as libc::size_t;

        let fd = socket.as_raw_fd();
        let ret = libc::recvmsg(fd, &mut msg, 0);
        if ret < 0 {
            return Err(Error::last_os_error());
        }

        let dst_addr = match get_destination_addr(&msg) {
            None => {
                let err = Error::new(ErrorKind::InvalidData, "missing destination address in msghdr");
                return Err(err);
            }
            Some(d) => d,
        };

        Ok((ret as usize, sockaddr_to_std(&src_addr)?, sockaddr_to_std(&dst_addr)?))
    }
}
<|endoftext|>


<commit_before>use std::io::{TcpStream, BufferedReader, IoResult, IoError, InvalidInput};
use regex::*;
use std::path::BytesContainer;
use std::slice::bytes;
use std::str::from_utf8;
use std::char::*;

static ID_TOKEN: &'static str = "Server-Id";
static LENGTH_TOKEN: &'static str = "Content-Length";

/*
 * Wrap a string in the right headers for it to be sent over the network.
 */
pub fn frame_msg(s: &str, server_id: uint) -> ~str {
    (make_content_length(s) + "\n" +
     make_id_hdr(server_id) + "\n" +
     s)
}

fn make_content_length(s: &str) -> ~str {
    LENGTH_TOKEN + ": " + s.as_bytes().len().to_str()
}

fn make_id_hdr(id: uint) -> ~str{
    ID_TOKEN + ": " + id.to_str()
}

fn parse_content_length(len_hdr: &str) -> IoResult<uint> {
    let re = regex!(r"Content-Length: (?P<length>\d+)");
    let strlen = re.captures(len_hdr).and_then(|c| Some(c.name("length")));
    let len: Option<uint> = strlen.and_then(|l| from_str(l));
    match len {
        Some(len) => Ok(len),
        None => Err(IoError{
            kind: InvalidInput,
            desc: "Failed parsing content length",
            detail: None,
        }),
    }
}

fn parse_server_id(id_hdr: &str) -> IoResult<uint> {
    let re = regex!(r"Server-Id: (?P<id>\d+)");
    let strid = re.captures(id_hdr).and_then(|c| Some(c.name("id")));
    let id: Option<uint> = strid.and_then(|i| from_str(i));
    match id {
        Some(uid) => Ok(uid),
        None => Err(IoError {
            kind: InvalidInput,
            desc: "Failed parsing server ID",
            detail: None,
        }),
    }
}

pub fn read_network_msg(mut reader: BufferedReader<TcpStream>) -> IoResult<~str> {
    let mut length: uint;
    let length = try!(reader.read_line().and_then(|l| parse_content_length(l)));
    let id_hdr = reader.read_line().map_err(|e| "Reading failed");
    let id = id_hdr.map(|i| parse_server_id(i));
    let mut buf: Vec<u8> = Vec::from_elem(length, 0u8);
    let content = try!(reader.read_exact(length));
    match content.container_as_str() {
        Some(s) => Ok(s.to_owned()),
        None => Err(IoError{
            kind: InvalidInput,
            desc: "Conversion of Network message from bytes to str failed",
            detail: None,
        }),
    }
}

#[cfg(test)]
mod test {
    use std::io::{TcpStream, BufferedReader, IoResult, IoError, InvalidInput};
    use std::io::net::ip::{SocketAddr, Ipv4Addr};
    use std::io::{Acceptor, Listener, TcpListener, TcpStream};
    use std::io::net::tcp::TcpAcceptor;

    use super::{parse_content_length, parse_server_id, read_network_msg,
                LENGTH_TOKEN, make_id_hdr, frame_msg};

    /*
     * Can we parse content length fields?
     */
    #[test]
    fn test_content_length() {
        assert!(parse_content_length(LENGTH_TOKEN + ": 800").unwrap() == 800);
        assert!(parse_content_length(LENGTH_TOKEN + ": 32").unwrap() == 32);
        assert!(parse_content_length(LENGTH_TOKEN + ": 0").unwrap() == 0);
        assert!(parse_content_length("buckets: 0").is_err());
        assert!(parse_content_length("Length 0").is_err());
    }

    /*
     * Can we create and parse server ID fields?
     */
    #[test]
    fn test_parse_id() {
        assert!(parse_server_id(make_id_hdr(53)).unwrap() == 53);
        assert!(parse_server_id(make_id_hdr(0)).unwrap() == 0);
        assert!(parse_server_id("buckets: 0").is_err());
        assert!(parse_server_id("Length 0").is_err());
    }

    /*
     * Spawns a server, listens, sends one message and tries to parse it.
     */
    #[test]
    fn test_read_network_msg() {
        let listen_addr = SocketAddr {
            ip: Ipv4Addr(127, 0, 0, 1),
            port: 8844,
        };
        let listener: TcpListener = TcpListener::bind(listen_addr).unwrap();
        let mut acceptor: TcpAcceptor = listener.listen().unwrap();
        spawn(proc() {
            let mut client_stream = TcpStream::connect(listen_addr);
            let msg = frame_msg("Hello world", 14);
            client_stream.write(msg.as_bytes());
        });
        for server_stream in acceptor.incoming() {
            let reader = BufferedReader::new(server_stream.unwrap());
            let result = read_network_msg(reader);
            assert!(result.is_ok());
            assert!(result.unwrap() == ~"Hello world");
            break;
        }
        drop(acceptor);
    }
}
<commit_msg>more parser cleanup<commit_after>use std::io::{TcpStream, BufferedReader, IoResult, IoError, InvalidInput};
use regex::*;
use std::path::BytesContainer;
use std::slice::bytes;
use std::str::from_utf8;
use std::char::*;

static ID_TOKEN: &'static str = "Server-Id";
static LENGTH_TOKEN: &'static str = "Content-Length";

/*
 * Wrap a string in the right headers for it to be sent over the network.
 */
pub fn frame_msg(s: &str, server_id: uint) -> ~str {
    (make_content_length(s) + "\n" +
     make_id_hdr(server_id) + "\n" +
     s)
}

fn make_content_length(s: &str) -> ~str {
    LENGTH_TOKEN + ": " + s.as_bytes().len().to_str()
}

fn make_id_hdr(id: uint) -> ~str{
    ID_TOKEN + ": " + id.to_str()
}

fn to_result<T>(ok: Option<T>, err: &'static str) -> Result<T, IoError> {
    match ok {
        Some(res) => Ok(res),
        None => Err(IoError{
            kind: InvalidInput,
            desc: err,
            detail: None,
        }),
    }
}

fn parse_content_length(len_hdr: &str) -> IoResult<uint> {
    to_result(regex!(r"Content-Length: (\d+)")
        .captures(len_hdr)
        .map(|c| c.at(1))
        .and_then(|l| from_str(l)), "Failed parsing content length")
}

fn parse_server_id(id_hdr: &str) -> IoResult<uint> {
    to_result(regex!(r"Server-Id: (\d+)")
        .captures(id_hdr)
        .map(|c| c.at(1))
        .and_then(|i| from_str(i)), "Failed parsing server ID")
}

pub fn read_network_msg(mut reader: BufferedReader<TcpStream>) -> IoResult<~str> {
    let length  = try!(parse_content_length(try!(reader.read_line())));
    let id      = try!(parse_server_id(     try!(reader.read_line())));
    let content = try!(reader.read_exact(length));
    to_result(content.container_as_str().map(|c| c.to_owned()),
        "Conversion of Network message from bytes to str failed")
}

#[cfg(test)]
mod test {
    use std::io::{TcpStream, BufferedReader, IoResult, IoError, InvalidInput};
    use std::io::net::ip::{SocketAddr, Ipv4Addr};
    use std::io::{Acceptor, Listener, TcpListener, TcpStream};
    use std::io::net::tcp::TcpAcceptor;

    use super::{parse_content_length, parse_server_id, read_network_msg,
                LENGTH_TOKEN, make_id_hdr, frame_msg};

    /*
     * Can we parse content length fields?
     */
    #[test]
    fn test_content_length() {
        assert!(parse_content_length(LENGTH_TOKEN + ": 800").unwrap() == 800);
        assert!(parse_content_length(LENGTH_TOKEN + ": 32").unwrap() == 32);
        assert!(parse_content_length(LENGTH_TOKEN + ": 0").unwrap() == 0);
        assert!(parse_content_length("buckets: 0").is_err());
        assert!(parse_content_length("Length 0").is_err());
    }

    /*
     * Can we create and parse server ID fields?
     */
    #[test]
    fn test_parse_id() {
        assert!(parse_server_id(make_id_hdr(53)).unwrap() == 53);
        assert!(parse_server_id(make_id_hdr(0)).unwrap() == 0);
        assert!(parse_server_id("buckets: 0").is_err());
        assert!(parse_server_id("Length 0").is_err());
    }

    /*
     * Spawns a server, listens, sends one message and tries to parse it.
     */
    #[test]
    fn test_read_network_msg() {
        let listen_addr = SocketAddr {
            ip: Ipv4Addr(127, 0, 0, 1),
            port: 8844,
        };
        let listener: TcpListener = TcpListener::bind(listen_addr).unwrap();
        let mut acceptor: TcpAcceptor = listener.listen().unwrap();
        spawn(proc() {
            let mut client_stream = TcpStream::connect(listen_addr);
            let msg = frame_msg("Hello world", 14);
            client_stream.write(msg.as_bytes());
        });
        for server_stream in acceptor.incoming() {
            let reader = BufferedReader::new(server_stream.unwrap());
            let result = read_network_msg(reader);
            assert!(result.is_ok());
            assert!(result.unwrap() == ~"Hello world");
            break;
        }
        drop(acceptor);
    }
}
<|endoftext|>


<commit_before>use neb::dovahkiin::expr::symbols::Symbol;
use neb::dovahkiin::expr::SExpr;

#[derive(Debug)]
pub struct Insert {}
impl Symbol for Insert {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Select {}
impl Symbol for Select {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Update {}
impl Symbol for Update {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Delete {}
impl Symbol for Delete {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}<commit_msg>planing symbol parameters<commit_after>use neb::dovahkiin::expr::symbols::Symbol;
use neb::dovahkiin::expr::SExpr;

// (insert-cell "<schema>" (hashmap "<key-1>" <value-1> "<key-2>" (hashmap "<key-3>" <value-2>)))
#[derive(Debug)]
pub struct Insert {}
impl Symbol for Insert {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Select {}
impl Symbol for Select {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Update {}
impl Symbol for Update {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Delete {}
impl Symbol for Delete {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}<|endoftext|>


<commit_before><commit_msg>Add result type<commit_after>use std::result::Result as RResult;

use error::TagError;

pub type Result<T> = RResult<T, TagError>;

<|endoftext|>


<commit_before>//! Maximum flows, matchings, and minimum cuts.
use super::{AdjListIterator, Graph};

/// Representation of a network flow problem with (optional) costs.
pub struct FlowGraph {
    /// Owned graph, managed by this FlowGraph object.
    pub graph: Graph,
    /// Edge capacities.
    pub cap: Vec<i64>,
    /// Edge cost per unit flow.
    pub cost: Vec<i64>,
}

impl FlowGraph {
    /// An upper limit to the flow.
    const INF: i64 = 0x3f3f_3f3f_3f3f_3f3f;

    /// Initializes an flow network with vmax vertices and no edges.
    pub fn new(vmax: usize, emax_hint: usize) -> Self {
        Self {
            graph: Graph::new(vmax, 2 * emax_hint),
            cap: Vec::with_capacity(2 * emax_hint),
            cost: Vec::with_capacity(2 * emax_hint),
        }
    }

    /// Adds an edge with specified directional capacities and cost per unit of
    /// flow. If only forward flow is allowed, rcap should be zero.
    pub fn add_edge(&mut self, u: usize, v: usize, cap: i64, rcap: i64, cost: i64) {
        self.cap.push(cap);
        self.cap.push(rcap);
        self.cost.push(cost);
        self.cost.push(-cost);
        self.graph.add_undirected_edge(u, v);
    }

    /// Dinic's algorithm to find the maximum flow from s to t where s != t.
    /// Generalizes the Hopcroft-Karp maximum bipartite matching algorithm.
    /// V^2E in general, min(V^(2/3),sqrt(E))E when all edges are unit capacity,
    /// sqrt(V)E when all vertices are unit capacity as in bipartite graphs.
    ///
    /// # Panics
    ///
    /// Panics if the maximum flow is 2^63 or larger.
    pub fn dinic(&self, s: usize, t: usize) -> (i64, Vec<i64>) {
        let mut flow = vec![0; self.graph.num_e()];
        let mut max_flow = 0;
        loop {
            let dist = self.dinic_search(s, &flow);
            if dist[t] == Self::INF {
                break;
            }
            // Keep track of adjacency lists to avoid revisiting blocked edges.
            let mut adj_iters = (0..self.graph.num_v())
                .map(|u| self.graph.adj_list(u).peekable())
                .collect::<Vec<_>>();
            max_flow += self.dinic_augment(s, t, Self::INF, &dist, &mut adj_iters, &mut flow);
        }
        (max_flow, flow)
    }

    // Compute BFS distances to restrict attention to shortest path edges.
    fn dinic_search(&self, s: usize, flow: &[i64]) -> Vec<i64> {
        let mut dist = vec![Self::INF; self.graph.num_v()];
        let mut q = ::std::collections::VecDeque::new();
        dist[s] = 0;
        q.push_back(s);
        while let Some(u) = q.pop_front() {
            for (e, v) in self.graph.adj_list(u) {
                if dist[v] == Self::INF && flow[e] < self.cap[e] {
                    dist[v] = dist[u] + 1;
                    q.push_back(v);
                }
            }
        }
        dist
    }

    // Pushes a blocking flow that increases the residual's s-t distance.
    fn dinic_augment(
        &self,
        u: usize,
        t: usize,
        f: i64,
        dist: &[i64],
        adj: &mut [::std::iter::Peekable<AdjListIterator>],
        flow: &mut [i64],
    ) -> i64 {
        if u == t {
            return f;
        }
        let mut df = 0;

        while let Some(&(e, v)) = adj[u].peek() {
            let rem_cap = (self.cap[e] - flow[e]).min(f - df);
            if rem_cap > 0 && dist[v] == dist[u] + 1 {
                let cf = self.dinic_augment(v, t, rem_cap, dist, adj, flow);
                flow[e] += cf;
                flow[e ^ 1] -= cf;
                df += cf;
                if df == f {
                    break;
                }
            }
            // The current edge is either saturated or blocked.
            adj[u].next();
        }
        df
    }

    /// After running maximum flow, use this to recover the dual minimum cut.
    pub fn min_cut(&self, dist: &[i64]) -> Vec<usize> {
        (0..self.graph.num_e())
            .filter(|&e| {
                let u = self.graph.endp[e ^ 1];
                let v = self.graph.endp[e];
                dist[u] < Self::INF && dist[v] == Self::INF
            })
            .collect()
    }

    /// Among all s-t maximum flows, finds one with minimum cost, assuming
    /// s != t and no negative-cost cycles.
    ///
    /// # Panics
    ///
    /// Panics if the flow or cost overflow a 64-bit signed integer.
    pub fn mcf(&self, s: usize, t: usize) -> (i64, i64, Vec<i64>) {
        let mut pot = vec![0; self.graph.num_v()];

        // Bellman-Ford deals with negative-cost edges at initialization.
        for _ in 1..self.graph.num_v() {
            for e in 0..self.graph.num_e() {
                if self.cap[e] > 0 {
                    let u = self.graph.endp[e ^ 1];
                    let v = self.graph.endp[e];
                    pot[v] = pot[v].min(pot[u] + self.cost[e]);
                }
            }
        }

        let mut flow = vec![0; self.graph.num_e()];
        let (mut min_cost, mut max_flow) = (0, 0);
        loop {
            let par = self.mcf_search(s, &flow, &mut pot);
            if par[t] == None {
                break;
            }
            let (dc, df) = self.mcf_augment(t, &par, &mut flow);
            min_cost += dc;
            max_flow += df;
        }
        (min_cost, max_flow, flow)
    }

    // Maintains Johnson's potentials to prevent negative-cost residual edges.
    // This allows running Dijkstra instead of the slower Bellman-Ford.
    fn mcf_search(&self, s: usize, flow: &[i64], pot: &mut [i64]) -> Vec<Option<usize>> {
        let mut vis = vec![false; self.graph.num_v()];
        let mut dist = vec![Self::INF; self.graph.num_v()];
        let mut par = vec![None; self.graph.num_v()];

        dist[s] = 0;
        while let Some(u) = (0..self.graph.num_v())
            .filter(|&u| !vis[u] && dist[u] < Self::INF)
            .min_by_key(|&u| dist[u] - pot[u])
        {
            vis[u] = true;
            pot[u] = dist[u];
            for (e, v) in self.graph.adj_list(u) {
                if dist[v] > dist[u] + self.cost[e] && flow[e] < self.cap[e] {
                    dist[v] = dist[u] + self.cost[e];
                    par[v] = Some(e);
                }
            }
        }
        par
    }

    // Pushes flow along an augmenting path of minimum cost.
    fn mcf_augment(&self, t: usize, par: &[Option<usize>], flow: &mut [i64]) -> (i64, i64) {
        let (mut dc, mut df) = (0, Self::INF);
        let mut u = t;
        while let Some(e) = par[u] {
            df = df.min(self.cap[e] - flow[e]);
            u = self.graph.endp[e ^ 1];
        }
        u = t;
        while let Some(e) = par[u] {
            flow[e] += df;
            flow[e ^ 1] -= df;
            dc += df * self.cost[e];
            u = self.graph.endp[e ^ 1];
        }
        (dc, df)
    }
}

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

    #[test]
    fn test_basic_flow() {
        let mut graph = FlowGraph::new(3, 2);
        graph.add_edge(0, 1, 4, 0, 0);
        graph.add_edge(1, 2, 3, 0, 0);

        let flow = graph.dinic(0, 2).0;
        assert_eq!(flow, 3);
    }

    #[test]
    fn test_min_cost_flow() {
        let mut graph = FlowGraph::new(4, 4);
        graph.add_edge(0, 1, 10, 0, -10);
        graph.add_edge(1, 2, 7, 0, 8);
        graph.add_edge(2, 3, 7, 0, 8);
        graph.add_edge(1, 3, 7, 0, 10);

        let (cost, flow, _) = graph.mcf(0, 3);
        assert_eq!(cost, 18);
        assert_eq!(flow, 10);
    }

    #[test]
    fn test_max_matching() {
        let mut graph = FlowGraph::new(14, 4);

        let source = 0;
        let sink = 13;

        //Vertex indices of "left hand side" of bipartite graph go from [left_start, right_start)
        let left_start = 1;
        //Vertex indices of "right hand side" of bipartite graph go from [right_start, sink)
        let right_start = 7;

        //Initialize source / sink connections; both left & right have 6 nodes
        for lhs_vertex in left_start..left_start + 6 {
            graph.add_edge(source, lhs_vertex, 1, 0, 0);
        }

        for rhs_vertex in right_start..right_start + 6 {
            graph.add_edge(rhs_vertex, sink, 1, 0, 0);
        }

        graph.add_edge(left_start + 0, right_start + 1, 1, 0, 0);
        graph.add_edge(left_start + 0, right_start + 2, 1, 0, 0);
        graph.add_edge(left_start + 2, right_start + 0, 1, 0, 0);
        graph.add_edge(left_start + 2, right_start + 3, 1, 0, 0);
        graph.add_edge(left_start + 3, right_start + 2, 1, 0, 0);
        graph.add_edge(left_start + 4, right_start + 2, 1, 0, 0);
        graph.add_edge(left_start + 4, right_start + 3, 1, 0, 0);
        graph.add_edge(left_start + 5, right_start + 5, 1, 0, 0);

        let (flow_amt, flow) = graph.dinic(source, sink);
        assert_eq!(flow_amt, 5);

        //L->R edges in maximum matching
        let left_right_edges = flow
            .into_iter()
            .enumerate()
            .filter(|&(_e, f)| f > 0)
            //map to u->v
            .map(|(e, _f)| (graph.graph.endp[e ^ 1], graph.graph.endp[e]))
            //leave out source and sink nodes
            .filter(|&(u, v)| u != source && v != sink)
            .collect::<Vec<_>>();

        assert_eq!(
            left_right_edges,
            vec![(1, 8), (3, 7), (4, 9), (5, 10), (6, 12)]
        );
    }
}
<commit_msg>use i64::MAX instead of 0x3f3f3f3f3f3f3f3f (#22)<commit_after>//! Maximum flows, matchings, and minimum cuts.
use super::{AdjListIterator, Graph};

/// Representation of a network flow problem with (optional) costs.
pub struct FlowGraph {
    /// Owned graph, managed by this FlowGraph object.
    pub graph: Graph,
    /// Edge capacities.
    pub cap: Vec<i64>,
    /// Edge cost per unit flow.
    pub cost: Vec<i64>,
}

impl FlowGraph {
    /// An upper limit to the flow.
    const INF: i64 = i64::MAX;

    /// Initializes an flow network with vmax vertices and no edges.
    pub fn new(vmax: usize, emax_hint: usize) -> Self {
        Self {
            graph: Graph::new(vmax, 2 * emax_hint),
            cap: Vec::with_capacity(2 * emax_hint),
            cost: Vec::with_capacity(2 * emax_hint),
        }
    }

    /// Adds an edge with specified directional capacities and cost per unit of
    /// flow. If only forward flow is allowed, rcap should be zero.
    pub fn add_edge(&mut self, u: usize, v: usize, cap: i64, rcap: i64, cost: i64) {
        self.cap.push(cap);
        self.cap.push(rcap);
        self.cost.push(cost);
        self.cost.push(-cost);
        self.graph.add_undirected_edge(u, v);
    }

    /// Dinic's algorithm to find the maximum flow from s to t where s != t.
    /// Generalizes the Hopcroft-Karp maximum bipartite matching algorithm.
    /// V^2E in general, min(V^(2/3),sqrt(E))E when all edges are unit capacity,
    /// sqrt(V)E when all vertices are unit capacity as in bipartite graphs.
    ///
    /// # Panics
    ///
    /// Panics if the maximum flow is 2^63 or larger.
    pub fn dinic(&self, s: usize, t: usize) -> (i64, Vec<i64>) {
        let mut flow = vec![0; self.graph.num_e()];
        let mut max_flow = 0;
        loop {
            let dist = self.dinic_search(s, &flow);
            if dist[t] == Self::INF {
                break;
            }
            // Keep track of adjacency lists to avoid revisiting blocked edges.
            let mut adj_iters = (0..self.graph.num_v())
                .map(|u| self.graph.adj_list(u).peekable())
                .collect::<Vec<_>>();
            max_flow += self.dinic_augment(s, t, Self::INF, &dist, &mut adj_iters, &mut flow);
        }
        (max_flow, flow)
    }

    // Compute BFS distances to restrict attention to shortest path edges.
    fn dinic_search(&self, s: usize, flow: &[i64]) -> Vec<i64> {
        let mut dist = vec![Self::INF; self.graph.num_v()];
        let mut q = ::std::collections::VecDeque::new();
        dist[s] = 0;
        q.push_back(s);
        while let Some(u) = q.pop_front() {
            for (e, v) in self.graph.adj_list(u) {
                if dist[v] == Self::INF && flow[e] < self.cap[e] {
                    dist[v] = dist[u] + 1;
                    q.push_back(v);
                }
            }
        }
        dist
    }

    // Pushes a blocking flow that increases the residual's s-t distance.
    fn dinic_augment(
        &self,
        u: usize,
        t: usize,
        f: i64,
        dist: &[i64],
        adj: &mut [::std::iter::Peekable<AdjListIterator>],
        flow: &mut [i64],
    ) -> i64 {
        if u == t {
            return f;
        }
        let mut df = 0;

        while let Some(&(e, v)) = adj[u].peek() {
            let rem_cap = (self.cap[e] - flow[e]).min(f - df);
            if rem_cap > 0 && dist[v] == dist[u] + 1 {
                let cf = self.dinic_augment(v, t, rem_cap, dist, adj, flow);
                flow[e] += cf;
                flow[e ^ 1] -= cf;
                df += cf;
                if df == f {
                    break;
                }
            }
            // The current edge is either saturated or blocked.
            adj[u].next();
        }
        df
    }

    /// After running maximum flow, use this to recover the dual minimum cut.
    pub fn min_cut(&self, dist: &[i64]) -> Vec<usize> {
        (0..self.graph.num_e())
            .filter(|&e| {
                let u = self.graph.endp[e ^ 1];
                let v = self.graph.endp[e];
                dist[u] < Self::INF && dist[v] == Self::INF
            })
            .collect()
    }

    /// Among all s-t maximum flows, finds one with minimum cost, assuming
    /// s != t and no negative-cost cycles.
    ///
    /// # Panics
    ///
    /// Panics if the flow or cost overflow a 64-bit signed integer.
    pub fn mcf(&self, s: usize, t: usize) -> (i64, i64, Vec<i64>) {
        let mut pot = vec![0; self.graph.num_v()];

        // Bellman-Ford deals with negative-cost edges at initialization.
        for _ in 1..self.graph.num_v() {
            for e in 0..self.graph.num_e() {
                if self.cap[e] > 0 {
                    let u = self.graph.endp[e ^ 1];
                    let v = self.graph.endp[e];
                    pot[v] = pot[v].min(pot[u] + self.cost[e]);
                }
            }
        }

        let mut flow = vec![0; self.graph.num_e()];
        let (mut min_cost, mut max_flow) = (0, 0);
        loop {
            let par = self.mcf_search(s, &flow, &mut pot);
            if par[t] == None {
                break;
            }
            let (dc, df) = self.mcf_augment(t, &par, &mut flow);
            min_cost += dc;
            max_flow += df;
        }
        (min_cost, max_flow, flow)
    }

    // Maintains Johnson's potentials to prevent negative-cost residual edges.
    // This allows running Dijkstra instead of the slower Bellman-Ford.
    fn mcf_search(&self, s: usize, flow: &[i64], pot: &mut [i64]) -> Vec<Option<usize>> {
        let mut vis = vec![false; self.graph.num_v()];
        let mut dist = vec![Self::INF; self.graph.num_v()];
        let mut par = vec![None; self.graph.num_v()];

        dist[s] = 0;
        while let Some(u) = (0..self.graph.num_v())
            .filter(|&u| !vis[u] && dist[u] < Self::INF)
            .min_by_key(|&u| dist[u] - pot[u])
        {
            vis[u] = true;
            pot[u] = dist[u];
            for (e, v) in self.graph.adj_list(u) {
                if dist[v] > dist[u] + self.cost[e] && flow[e] < self.cap[e] {
                    dist[v] = dist[u] + self.cost[e];
                    par[v] = Some(e);
                }
            }
        }
        par
    }

    // Pushes flow along an augmenting path of minimum cost.
    fn mcf_augment(&self, t: usize, par: &[Option<usize>], flow: &mut [i64]) -> (i64, i64) {
        let (mut dc, mut df) = (0, Self::INF);
        let mut u = t;
        while let Some(e) = par[u] {
            df = df.min(self.cap[e] - flow[e]);
            u = self.graph.endp[e ^ 1];
        }
        u = t;
        while let Some(e) = par[u] {
            flow[e] += df;
            flow[e ^ 1] -= df;
            dc += df * self.cost[e];
            u = self.graph.endp[e ^ 1];
        }
        (dc, df)
    }
}

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

    #[test]
    fn test_basic_flow() {
        let mut graph = FlowGraph::new(3, 2);
        graph.add_edge(0, 1, 4, 0, 0);
        graph.add_edge(1, 2, 3, 0, 0);

        let flow = graph.dinic(0, 2).0;
        assert_eq!(flow, 3);
    }

    #[test]
    fn test_min_cost_flow() {
        let mut graph = FlowGraph::new(4, 4);
        graph.add_edge(0, 1, 10, 0, -10);
        graph.add_edge(1, 2, 7, 0, 8);
        graph.add_edge(2, 3, 7, 0, 8);
        graph.add_edge(1, 3, 7, 0, 10);

        let (cost, flow, _) = graph.mcf(0, 3);
        assert_eq!(cost, 18);
        assert_eq!(flow, 10);
    }

    #[test]
    fn test_max_matching() {
        let mut graph = FlowGraph::new(14, 4);

        let source = 0;
        let sink = 13;

        //Vertex indices of "left hand side" of bipartite graph go from [left_start, right_start)
        let left_start = 1;
        //Vertex indices of "right hand side" of bipartite graph go from [right_start, sink)
        let right_start = 7;

        //Initialize source / sink connections; both left & right have 6 nodes
        for lhs_vertex in left_start..left_start + 6 {
            graph.add_edge(source, lhs_vertex, 1, 0, 0);
        }

        for rhs_vertex in right_start..right_start + 6 {
            graph.add_edge(rhs_vertex, sink, 1, 0, 0);
        }

        graph.add_edge(left_start + 0, right_start + 1, 1, 0, 0);
        graph.add_edge(left_start + 0, right_start + 2, 1, 0, 0);
        graph.add_edge(left_start + 2, right_start + 0, 1, 0, 0);
        graph.add_edge(left_start + 2, right_start + 3, 1, 0, 0);
        graph.add_edge(left_start + 3, right_start + 2, 1, 0, 0);
        graph.add_edge(left_start + 4, right_start + 2, 1, 0, 0);
        graph.add_edge(left_start + 4, right_start + 3, 1, 0, 0);
        graph.add_edge(left_start + 5, right_start + 5, 1, 0, 0);

        let (flow_amt, flow) = graph.dinic(source, sink);
        assert_eq!(flow_amt, 5);

        //L->R edges in maximum matching
        let left_right_edges = flow
            .into_iter()
            .enumerate()
            .filter(|&(_e, f)| f > 0)
            //map to u->v
            .map(|(e, _f)| (graph.graph.endp[e ^ 1], graph.graph.endp[e]))
            //leave out source and sink nodes
            .filter(|&(u, v)| u != source && v != sink)
            .collect::<Vec<_>>();

        assert_eq!(
            left_right_edges,
            vec![(1, 8), (3, 7), (4, 9), (5, 10), (6, 12)]
        );
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use middle::types as untyped;

#[derive(Clone, Debug)]
pub struct Type<T> {
    untyped: untyped::Type,
    _marker: PhantomData<*mut T>,
}

impl<T> Type<T> {
    fn make(untyped: untyped::Type) -> Self {
        Type {
            untyped: untyped,
            _marker: PhantomData,
        }
    }

    pub fn into_untyped(self) -> untyped::Type {
        self.untyped
    }
}

pub trait FfiType : Sized {
    fn get_type() -> Type<Self>;
}

macro_rules! impl_ffi_type {
    ($type_:ty, $cons:ident) => {
        impl FfiType for $type_ {
            fn get_type() -> Type<Self> {
                Type::make(untyped::Type::$cons())
            }
        }
    };
    ($type_:ident) => {
        impl_ffi_type!($type_, $type_);
    };
}

impl_ffi_type!(u8);
impl_ffi_type!(i8);
impl_ffi_type!(u16);
impl_ffi_type!(i16);
impl_ffi_type!(u32);
impl_ffi_type!(i32);
impl_ffi_type!(u64);
impl_ffi_type!(i64);
impl_ffi_type!(f32);
impl_ffi_type!(f64);
impl_ffi_type!(usize);
impl_ffi_type!(isize);
impl_ffi_type!((), void);

impl<T> FfiType for *const T {
    fn get_type() -> Type<Self> { Type::make(untyped::Type::pointer()) }
}

impl<T> FfiType for *mut T {
    fn get_type() -> Type<Self> { Type::make(untyped::Type::pointer()) }
}
<commit_msg>rudimentary complex support<commit_after>use std::marker::PhantomData;

use middle::types as untyped;

#[derive(Clone, Debug)]
pub struct Type<T> {
    untyped: untyped::Type,
    _marker: PhantomData<*mut T>,
}

impl<T> Type<T> {
    fn make(untyped: untyped::Type) -> Self {
        Type {
            untyped: untyped,
            _marker: PhantomData,
        }
    }

    pub fn into_untyped(self) -> untyped::Type {
        self.untyped
    }
}

pub trait FfiType : Sized {
    fn get_type() -> Type<Self>;
}

macro_rules! impl_ffi_type {
    ($type_:ty, $cons:ident) => {
        impl FfiType for $type_ {
            fn get_type() -> Type<Self> {
                Type::make(untyped::Type::$cons())
            }
        }
    };
    ($type_:ident) => {
        impl_ffi_type!($type_, $type_);
    };
}

impl_ffi_type!(u8);
impl_ffi_type!(i8);
impl_ffi_type!(u16);
impl_ffi_type!(i16);
impl_ffi_type!(u32);
impl_ffi_type!(i32);
impl_ffi_type!(u64);
impl_ffi_type!(i64);
impl_ffi_type!(f32);
impl_ffi_type!(f64);
impl_ffi_type!(usize);
impl_ffi_type!(isize);
impl_ffi_type!((), void);

/// Laid out the same as C11 `float complex` and C++11
/// `std::complex<float>`.
///
/// # Warning
///
/// This type does not obey the ABI, and as such should not be passed by
/// value to or from a C or C++ function. Passing it via a pointer or
/// via libffi-rs is okay.
#[allow(non_camel_case_types)]
pub type c_c32 = [f32; 2];

/// Laid out the same as C11 `double complex` and C++11
/// `std::complex<double>`.
///
/// # Warning
///
/// This type does not obey the ABI, and as such should not be passed by
/// value to or from a C or C++ function. Passing it via a pointer or
/// via libffi-rs is okay.
#[allow(non_camel_case_types)]
pub type c_c64 = [f64; 2];

impl_ffi_type!(c_c32, c32);
impl_ffi_type!(c_c64, c64);

impl<T> FfiType for *const T {
    fn get_type() -> Type<Self> { Type::make(untyped::Type::pointer()) }
}

impl<T> FfiType for *mut T {
    fn get_type() -> Type<Self> { Type::make(untyped::Type::pointer()) }
}
<|endoftext|>


<commit_before>use std::env;
use support::{basic_manifest, project};

#[test]
fn collision_dylib() {
    // Path dependencies don't include metadata hash in filename for dylibs.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [workspace]
            members = ["a", "b"]
            "#,
        )
        .file(
            "a/Cargo.toml",
            r#"
            [package]
            name = "a"
            version = "1.0.0"

            [lib]
            crate-type = ["dylib"]
            "#,
        )
        .file("a/src/lib.rs", "")
        .file(
            "b/Cargo.toml",
            r#"
            [package]
            name = "b"
            version = "1.0.0"

            [lib]
            crate-type = ["dylib"]
            name = "a"
            "#,
        )
        .file("b/src/lib.rs", "")
        .build();

    p.cargo("build")
        .with_stderr_contains(&format!("\
[WARNING] output filename collision.
The lib target `a` in package `b v1.0.0 ([..]/foo/b)` has the same output filename as the lib target `a` in package `a v1.0.0 ([..]/foo/a)`.
Colliding filename is: [..]/foo/target/debug/deps/{}a{}
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future, see https://github.com/rust-lang/cargo/issues/6313
", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX))
        .run();
}

#[test]
fn collision_example() {
    // Examples in a workspace can easily collide.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [workspace]
            members = ["a", "b"]
            "#,
        )
        .file("a/Cargo.toml", &basic_manifest("a", "1.0.0"))
        .file("a/examples/ex1.rs", "fn main() {}")
        .file("b/Cargo.toml", &basic_manifest("b", "1.0.0"))
        .file("b/examples/ex1.rs", "fn main() {}")
        .build();

    p.cargo("build --examples")
        .with_stderr_contains("\
[WARNING] output filename collision.
The example target `ex1` in package `b v1.0.0 ([..]/foo/b)` has the same output filename as the example target `ex1` in package `a v1.0.0 ([..]/foo/a)`.
Colliding filename is: [..]/foo/target/debug/examples/ex1[EXE]
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future, see https://github.com/rust-lang/cargo/issues/6313
")
        .run();
}

#[test]
fn collision_export() {
    // --out-dir combines some things which can cause conflicts.
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("examples/foo.rs", "fn main() {}")
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build --out-dir=out -Z unstable-options --bins --examples")
        .masquerade_as_nightly_cargo()
        .with_stderr_contains("\
[WARNING] `--out-dir` filename collision.
The example target `foo` in package `foo v1.0.0 ([..]/foo)` has the same output filename as the bin target `foo` in package `foo v1.0.0 ([..]/foo)`.
Colliding filename is: [..]/foo/out/foo[EXE]
The exported filenames should be unique.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future, see https://github.com/rust-lang/cargo/issues/6313
")
        .run();
}
<commit_msg>Fix windows failure on collision_dylib.<commit_after>use std::env;
use support::{basic_manifest, project};

#[test]
fn collision_dylib() {
    // Path dependencies don't include metadata hash in filename for dylibs.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [workspace]
            members = ["a", "b"]
            "#,
        )
        .file(
            "a/Cargo.toml",
            r#"
            [package]
            name = "a"
            version = "1.0.0"

            [lib]
            crate-type = ["dylib"]
            "#,
        )
        .file("a/src/lib.rs", "")
        .file(
            "b/Cargo.toml",
            r#"
            [package]
            name = "b"
            version = "1.0.0"

            [lib]
            crate-type = ["dylib"]
            name = "a"
            "#,
        )
        .file("b/src/lib.rs", "")
        .build();

    // j=1 is required because on windows you'll get an error because
    // two processes will be writing to the file at the same time.
    p.cargo("build -j=1")
        .with_stderr_contains(&format!("\
[WARNING] output filename collision.
The lib target `a` in package `b v1.0.0 ([..]/foo/b)` has the same output filename as the lib target `a` in package `a v1.0.0 ([..]/foo/a)`.
Colliding filename is: [..]/foo/target/debug/deps/{}a{}
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future, see https://github.com/rust-lang/cargo/issues/6313
", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX))
        .run();
}

#[test]
fn collision_example() {
    // Examples in a workspace can easily collide.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [workspace]
            members = ["a", "b"]
            "#,
        )
        .file("a/Cargo.toml", &basic_manifest("a", "1.0.0"))
        .file("a/examples/ex1.rs", "fn main() {}")
        .file("b/Cargo.toml", &basic_manifest("b", "1.0.0"))
        .file("b/examples/ex1.rs", "fn main() {}")
        .build();

    p.cargo("build --examples")
        .with_stderr_contains("\
[WARNING] output filename collision.
The example target `ex1` in package `b v1.0.0 ([..]/foo/b)` has the same output filename as the example target `ex1` in package `a v1.0.0 ([..]/foo/a)`.
Colliding filename is: [..]/foo/target/debug/examples/ex1[EXE]
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future, see https://github.com/rust-lang/cargo/issues/6313
")
        .run();
}

#[test]
fn collision_export() {
    // --out-dir combines some things which can cause conflicts.
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
        .file("examples/foo.rs", "fn main() {}")
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build --out-dir=out -Z unstable-options --bins --examples")
        .masquerade_as_nightly_cargo()
        .with_stderr_contains("\
[WARNING] `--out-dir` filename collision.
The example target `foo` in package `foo v1.0.0 ([..]/foo)` has the same output filename as the bin target `foo` in package `foo v1.0.0 ([..]/foo)`.
Colliding filename is: [..]/foo/out/foo[EXE]
The exported filenames should be unique.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future, see https://github.com/rust-lang/cargo/issues/6313
")
        .run();
}
<|endoftext|>


<commit_before>//! A parent module

use self::basictype::BasicType;
use self::operator::OperatorType;
use self::read::tokenize;

pub mod basictype;
pub mod operator;
pub mod read;

#[deriving(Show)]
#[deriving(Clone)]
pub enum SExpr {
    Cons(DataType, Box<SExpr>),
    Nil,
}

#[deriving(Show)]
#[deriving(Clone)]
pub enum DataType {
    Operator(OperatorType),
    Literal(BasicType)
}

pub fn car(sexpr: &SExpr) -> Result<DataType, bool> {
    match sexpr {
        &Cons(ref x, _) => Ok(x.clone()),
        &Nil        => Err(false) //need to figure out how to represent nil
    }
}

pub fn cdr(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Cons(_, box ref dorsal) => Ok(dorsal.clone()),
        &Nil    => Err(false)
    }
}
<commit_msg>updated car and cdr... hopefully less wrong<commit_after>//! A parent module

use self::basictype::BasicType;
use self::operator::OperatorType;
use self::read::tokenize;

pub mod basictype;
pub mod operator;
pub mod read;

#[deriving(Show)]
#[deriving(Clone)]
pub enum SExpr {
    Data(DataType),
    Cons(Box<SExpr>, Box<SExpr>),
    Nil,
}

#[deriving(Show)]
#[deriving(Clone)]
pub enum DataType {
    Operator(OperatorType),
    Literal(BasicType)
}

pub fn car(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Data(ref anterior)     => Ok(Data(anterior.clone())),
        &Cons(ref anterior, _)  => Ok(*anterior.clone()),
        &Nil        => Err(false) //need to figure out how to represent nil
    }
}

pub fn cdr(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Cons(_, ref dorsal)    => Ok(Cons(box *dorsal.clone(), box Nil)),
        &Nil | &Data(_)         => Err(false)
    }
}
<|endoftext|>


<commit_before>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![feature(duration_span)]

extern crate argparse;
extern crate num;

use num::{Num, Zero, One, Signed};

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic]=u[ncells-1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie-1];
        }

        // conservative difference
        for ic in ifirst .. ilast {
            u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn min_dx(x: &[f64]) -> f64 {
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let mdx = x.windows(2) // iterator for adjacent pairs of a slice
               .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
               .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`
    mdx
}

#[test]
fn test_min_dx() {
    use std::iter::FromIterator;
    use std::cmp::Ordering;

    fn sub<T: Num + Copy>(lhs: &[T], rhs: &[T]) -> Vec<T> {
        Vec::from_iter (lhs.iter().zip(rhs.iter()) .map(|(&x,&y)| x - y ) )
    }

    // 1. prepare non-equidistant vector `x`
    let base_dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * base_dx).cos().abs() ) );

    x.sort_by(|&x, &y|
        if      x < y { Ordering::Less }
        else if x > y { Ordering::Greater }
        else { Ordering::Equal } );

    let delta_x = sub(&x, &[0.7295467223444416, 0.7556433468867207, 0.7894463883160331,
                            0.8284895327495356, 0.9760168013869176, 0.9938640428738624]);

    let inf_norm = delta_x .iter() .fold(delta_x[0].abs(), |x1, x2| (x1).max((*x2).abs()));

    assert!(inf_norm < 1e-10, "inf_norm");

    // classical way
    let mut min_dx1 = std::f64::MAX;
    for i in 0 .. x.len()-1 {
        min_dx1 = min_dx1.min(x[i+1]-x[i]);
    }

    // functional way
    let min_dx2 = min_dx(&x);
    let abs_delta = (min_dx1 - min_dx2).abs();
    println!("abs_delta : {} min_dx1 : {} min_dx2 : {} x : {:?}", abs_delta, min_dx1, min_dx2, x);
    assert!(abs_delta < 1e-10, "min_dx");
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+1;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    let mindx = min_dx(&x);
    let dt = cfl*mindx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u);
        }
    });
    println!("elapsed time: {}", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<commit_msg>reformat.<commit_after>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![feature(duration_span)]

extern crate argparse;
extern crate num;

use num::{Num, Zero, One, Signed};

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn min_dx(x: &[f64]) -> f64 {
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let mdx = x.windows(2) // iterator for adjacent pairs of a slice
               .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
               .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`
    mdx
}

#[test]
fn test_min_dx() {
    use std::iter::FromIterator;
    use std::cmp::Ordering;

    fn sub<T: Num + Copy>(lhs: &[T], rhs: &[T]) -> Vec<T> {
        Vec::from_iter (lhs.iter().zip(rhs.iter()) .map(|(&x,&y)| x - y ) )
    }

    // 1. prepare non-equidistant vector `x`
    let base_dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * base_dx).cos().abs() ) );

    x.sort_by(|&x, &y|
        if      x < y { Ordering::Less }
        else if x > y { Ordering::Greater }
        else { Ordering::Equal } );

    let delta_x = sub(&x, &[0.7295467223444416, 0.7556433468867207, 0.7894463883160331,
                            0.8284895327495356, 0.9760168013869176, 0.9938640428738624]);

    let inf_norm = delta_x .iter() .fold(delta_x[0].abs(), |x1, x2| (x1).max((*x2).abs()));

    assert!(inf_norm < 1e-10, "inf_norm");

    // classical way
    let mut min_dx1 = std::f64::MAX;
    for i in 0 .. x.len()-1 {
        min_dx1 = min_dx1.min(x[i+1]-x[i]);
    }

    // functional way
    let min_dx2 = min_dx(&x);
    let abs_delta = (min_dx1 - min_dx2).abs();
    println!("abs_delta : {} min_dx1 : {} min_dx2 : {} x : {:?}", abs_delta, min_dx1, min_dx2, x);
    assert!(abs_delta < 1e-10, "min_dx");
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic]=u[ncells-1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie-1];
        }

        // conservative difference
        for ic in ifirst .. ilast {
            u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+1;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    let mindx = min_dx(&x);
    let dt = cfl*mindx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u);
        }
    });
    println!("elapsed time: {}", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<|endoftext|>


<commit_before>use jeebie::utils::is_set;

pub struct GPU {
    mode: Mode,
    line: u32,
    cycles: u32,
    vram: VideoMemory
}

/// Video memory and related data/registers
/// The main VRAM (`data`) is used for the following values:
///     8000-87FF	Tile set #1: tiles 0-127
///     8800-8FFF	Tile set #1: tiles 128-255 Tile set #0: tiles -1 to -128
///     9000-97FF	Tile set #0: tiles 0-127
///     9800-9BFF	Tile map #0
///     9C00-9FFF	Tile map #1
///
/// There are 2 tile sets of 256 tiles, but 128 tiles are shared between them, so the
/// total amounts to 384 tiles.
/// The tile maps hold indexes to a corresponding tile in the tilesets.
/// Pixel data is 2 bits and is split between two adjacent bytes, low bit first:
///
///     1 0 0 0 1 1 0 1 -- 0x8000
///     0 1 1 0 1 0 1 1 -- 0x8001
///
///     1 2 2 0 3 1 2 3 -- pixel value (0 to 3)
///
/// The rest of the memory (`oam`) is used for sprite data and addressed separately
/// from FE00 to FE9F.
pub struct VideoMemory {
    data: [u8; 8192],
    oam: [u8; 160],
}

///  Mode 0 (HBlank): The LCD controller is in the H-Blank period and
///          the CPU can access both the display RAM (8000h-9FFFh)
///          and OAM (FE00h-FE9Fh)
///
///  Mode 1 (VBlank): The LCD controller is in the V-Blank period (or the
///          display is disabled) and the CPU can access both the
///          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
///
///  Mode 2 (OAMRead): The LCD controller is reading from OAM memory.
///          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
///          during this period.
///
///  Mode 3 (VRAMRead): The LCD controller is reading from both OAM and VRAM,
///          The CPU <cannot> access OAM and VRAM during this period.
///          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
enum Mode {
    HBlank,
    VBlank,
    OAMRead,
    VRAMRead,
}

/// An enum representing the possible color values for a pixel in the original GB.
/// While the GB is said to be monochromatic, it can actually display 4 different shades.
#[derive(Copy, Clone, PartialEq, Debug)]
enum GBColor {
    // white, rgb #FFFFFF
    Off = 0,
    // light grey, rgb #C0C0C0
    On33 = 1,
    // dark grey, rgb #606060
    On66 = 2,
    // black, rgb #000000
    On = 3,
}

impl GBColor {
    pub fn from_u8(number: u8) -> GBColor {
        match number {
            0 => GBColor::Off,
            1 => GBColor::On33,
            2 => GBColor::On66,
            3 => GBColor::On,
            _ => panic!("Invalid color value {}", number),
        }
    }
}

/// An enum used to discriminate tilesets (and maps)
enum TileSelector {
    Set0, Set1
}

/// An enum for sprite size mode (8x8 or 8x16)
enum SpriteSize {
    Size8, Size16
}

/// LCD Control register data
///     Bit 7 - LCD Display Enable             (0=Off, 1=On)
///     Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)
///     Bit 5 - Window Display Enable          (0=Off, 1=On)
///     Bit 4 - BG & Window Tile Data Select   (0=8800-97FF, 1=8000-8FFF)
///     Bit 3 - BG Tile Map Display Select     (0=9800-9BFF, 1=9C00-9FFF)
///     Bit 2 - OBJ (Sprite) Size              (0=8x8, 1=8x16)
///     Bit 1 - OBJ (Sprite) Display Enable    (0=Off, 1=On)
///     Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
struct LCDControl {
    lcd_enable: bool,
    window_tile_map: TileSelector,
    window_enable: bool,
    bgw_tile_data_select: TileSelector,
    bg_tile_map: TileSelector,
    sprite_size: SpriteSize,
    sprite_enable: bool,
    bg_enable: bool,
}

impl LCDControl {
    pub fn set_from_u8(&mut self, data: u8) {
        self.lcd_enable = if is_set(data, 7) { true } else { false };
        self.window_tile_map = if is_set(data, 6) { TileSelector::Set1 } else { TileSelector::Set0 };
        self.window_enable = if is_set(data, 5) { true } else { false };
        self.bgw_tile_data_select = if is_set(data, 4) { TileSelector::Set1 } else { TileSelector::Set0 };
        self.bg_tile_map = if is_set(data, 3) { TileSelector::Set1 } else { TileSelector::Set0 };
        self.sprite_size = if is_set(data, 2) { SpriteSize::Size16 } else { SpriteSize::Size8 };
        self.sprite_enable = if is_set(data, 1) { true } else { false };
        self.bg_enable = if is_set(data, 0) { true } else { false };
    }
}

/// A tile is an 8x8 square of pixels, each one stored in one of the VRAM's tilesets.
struct Tile {
    pixels: [GBColor; 64],
}

impl Tile {
    pub fn new() -> Tile {
        Tile { pixels: [GBColor::Off; 64] }
    }
}

impl GPU {
    pub fn new() -> GPU {
        GPU {
            mode: Mode::HBlank,
            line: 0,
            cycles: 0,
            vram: VideoMemory {
                data: [0; 8192],
                oam: [0; 160],
            },
        }
    }

    /// Retrieves Tile information from the VRAM.
    /// A tile is held in 16 bytes in the VRAM, enough information for 64 pixels (8x8 matrix, 2 bits per pixel).
    /// When selecting tiles from Set #1, the index 0 represents tile -128 (equal to tile 128 from Set #0)
    fn get_tile(&self, set: TileSelector, tile_index: usize) -> Tile {
        // Set1 starts after 128 tiles, or after 16 * 128 = 2048 (0x800) bytes
        let offset = if let TileSelector::Set1 = set { 0x800 } else { 0 };
        let start_addr = (offset + tile_index) * 0x10;
        let end_addr = start_addr + 0x10;

        let mut addr = start_addr;
        let mut pixels = [GBColor::Off; 64];

        while addr < end_addr {
            let (low, high) = (self.vram.data[addr], self.vram.data[addr + 1]);

            for i in 0..8 {
                let low_bit = (low >> i) & 0x01;
                let high_bit = (high >> i) & 0x01;

                let pixel_value = GBColor::from_u8(low_bit + high_bit * 2);
                // px 0..7, then 8..15
                let pixel_addr = (addr / 2) * 8 + i;
                pixels[pixel_addr as usize] = pixel_value;
            }

            addr += 2;
        }

        Tile { pixels: pixels }
    }

    pub fn write_vram(&mut self, addr: usize, value: u8) {
        self.vram.data[addr] = value;
    }

    pub fn read_vram(&self, addr: usize) -> u8 {
        self.vram.data[addr]
    }

    pub fn write_oam(&mut self, addr: usize, value: u8) {
        self.vram.oam[addr] = value;
    }

    pub fn read_oam(&self, addr: usize) -> u8 {
        self.vram.oam[addr]
    }

    /// Emulates the GPU.
    /// This function should be called after an instruction is executed by the CPU,
    /// `delta` is the number of cycles passed from the last instruction.
    pub fn emulate(&mut self, delta: u32) {

        self.cycles += delta;

        match self.mode {
            Mode::OAMRead => {
                if self.cycles >= 80 {
                    self.cycles = 0;
                    self.mode = Mode::VRAMRead;
                }
            }
            Mode::VRAMRead => {
                if self.cycles >= 172 {
                    self.cycles = 0;
                    self.mode = Mode::HBlank;

                    // TODO: scanline is done, write it to framebuffer
                }
            }
            Mode::HBlank => {
                if self.cycles >= 204 {
                    self.cycles = 0;
                    self.line += 1;

                    self.mode = if self.line == 143 {
                        Mode::VBlank
                    } else {
                        Mode::OAMRead
                    };
                }
            }
            Mode::VBlank => {
                if self.cycles >= 456 {
                    self.mode = Mode::HBlank;
                    self.line += 1;

                    if self.line > 153 {
                        self.mode = Mode::OAMRead;
                        self.line = 0;
                    }
                }
            }
        }
    }
}

#[test]
fn get_tile_test() {
    let mut gpu = GPU::new();
    // write first line of tile #0 in set #0
    // pixels should be: 0 1 2 3 3 2 1 0
    gpu.write_vram(0, 0b0101_1010u8);
    gpu.write_vram(1, 0b0011_1100u8);

    let tile = gpu.get_tile(TileSelector::Set0, 0);

    assert_eq!(tile.pixels[0], GBColor::Off);
    assert_eq!(tile.pixels[1], GBColor::On33);
    assert_eq!(tile.pixels[2], GBColor::On66);
    assert_eq!(tile.pixels[3], GBColor::On);

    assert_eq!(tile.pixels[4], GBColor::On);
    assert_eq!(tile.pixels[5], GBColor::On66);
    assert_eq!(tile.pixels[6], GBColor::On33);
    assert_eq!(tile.pixels[7], GBColor::Off);

    // rest of the pixels are off
    for i in 8..64 {
        assert_eq!(tile.pixels[i], GBColor::Off);
    }
}<commit_msg>Added LCDC to GPU struct<commit_after>use jeebie::utils::is_set;

pub struct GPU {
    mode: Mode,
    line: u32,
    cycles: u32,
    vram: VideoMemory,
    lcdc: LCDControl,
}

/// Video memory and related data/registers
/// The main VRAM (`data`) is used for the following values:
///     8000-87FF	Tile set #1: tiles 0-127
///     8800-8FFF	Tile set #1: tiles 128-255 Tile set #0: tiles -1 to -128
///     9000-97FF	Tile set #0: tiles 0-127
///     9800-9BFF	Tile map #0
///     9C00-9FFF	Tile map #1
///
/// There are 2 tile sets of 256 tiles, but 128 tiles are shared between them, so the
/// total amounts to 384 tiles.
/// The tile maps hold indexes to a corresponding tile in the tilesets.
/// Pixel data is 2 bits and is split between two adjacent bytes, low bit first:
///
///     1 0 0 0 1 1 0 1 -- 0x8000
///     0 1 1 0 1 0 1 1 -- 0x8001
///
///     1 2 2 0 3 1 2 3 -- pixel value (0 to 3)
///
/// The rest of the memory (`oam`) is used for sprite data and addressed separately
/// from FE00 to FE9F.
pub struct VideoMemory {
    data: [u8; 8192],
    oam: [u8; 160],
}

///  Mode 0 (HBlank): The LCD controller is in the H-Blank period and
///          the CPU can access both the display RAM (8000h-9FFFh)
///          and OAM (FE00h-FE9Fh)
///
///  Mode 1 (VBlank): The LCD controller is in the V-Blank period (or the
///          display is disabled) and the CPU can access both the
///          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
///
///  Mode 2 (OAMRead): The LCD controller is reading from OAM memory.
///          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
///          during this period.
///
///  Mode 3 (VRAMRead): The LCD controller is reading from both OAM and VRAM,
///          The CPU <cannot> access OAM and VRAM during this period.
///          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
enum Mode {
    HBlank,
    VBlank,
    OAMRead,
    VRAMRead,
}

/// An enum representing the possible color values for a pixel in the original GB.
/// While the GB is said to be monochromatic, it can actually display 4 different shades.
#[derive(Copy, Clone, PartialEq, Debug)]
enum GBColor {
    // white, rgb #FFFFFF
    Off = 0,
    // light grey, rgb #C0C0C0
    On33 = 1,
    // dark grey, rgb #606060
    On66 = 2,
    // black, rgb #000000
    On = 3,
}

impl GBColor {
    pub fn from_u8(number: u8) -> GBColor {
        match number {
            0 => GBColor::Off,
            1 => GBColor::On33,
            2 => GBColor::On66,
            3 => GBColor::On,
            _ => panic!("Invalid color value {}", number),
        }
    }
}

/// An enum used to discriminate tilesets (and maps)
enum TileSelector {
    Set0, Set1
}

/// An enum for sprite size mode (8x8 or 8x16)
enum SpriteSize {
    Size8, Size16
}

/// LCD Control register data
///     Bit 7 - LCD Display Enable             (0=Off, 1=On)
///     Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)
///     Bit 5 - Window Display Enable          (0=Off, 1=On)
///     Bit 4 - BG & Window Tile Data Select   (0=8800-97FF, 1=8000-8FFF)
///     Bit 3 - BG Tile Map Display Select     (0=9800-9BFF, 1=9C00-9FFF)
///     Bit 2 - OBJ (Sprite) Size              (0=8x8, 1=8x16)
///     Bit 1 - OBJ (Sprite) Display Enable    (0=Off, 1=On)
///     Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
struct LCDControl {
    lcd_enable: bool,
    window_tile_map: TileSelector,
    window_enable: bool,
    bgw_tile_data_select: TileSelector,
    bg_tile_map: TileSelector,
    sprite_size: SpriteSize,
    sprite_enable: bool,
    bg_enable: bool,
}

impl LCDControl {

    pub fn new() -> LCDControl {
        LCDControl {
            lcd_enable: false,
            window_tile_map: TileSelector::Set0,
            window_enable: false,
            bgw_tile_data_select: TileSelector::Set0,
            bg_tile_map: TileSelector::Set0,
            sprite_size: SpriteSize::Size8,
            sprite_enable: false,
            bg_enable: false,
        }
    }

    /// Sets LCDC data from a byte value
    pub fn set_from_u8(&mut self, data: u8) {
        self.lcd_enable = if is_set(data, 7) { true } else { false };
        self.window_tile_map = if is_set(data, 6) { TileSelector::Set1 } else { TileSelector::Set0 };
        self.window_enable = if is_set(data, 5) { true } else { false };
        self.bgw_tile_data_select = if is_set(data, 4) { TileSelector::Set1 } else { TileSelector::Set0 };
        self.bg_tile_map = if is_set(data, 3) { TileSelector::Set1 } else { TileSelector::Set0 };
        self.sprite_size = if is_set(data, 2) { SpriteSize::Size16 } else { SpriteSize::Size8 };
        self.sprite_enable = if is_set(data, 1) { true } else { false };
        self.bg_enable = if is_set(data, 0) { true } else { false };
    }
}

/// A tile is an 8x8 square of pixels, each one stored in one of the VRAM's tilesets.
struct Tile {
    pixels: [GBColor; 64],
}

impl Tile {
    pub fn new() -> Tile {
        Tile { pixels: [GBColor::Off; 64] }
    }
}

impl GPU {
    pub fn new() -> GPU {
        GPU {
            mode: Mode::HBlank,
            line: 0,
            cycles: 0,
            vram: VideoMemory {
                data: [0; 8192],
                oam: [0; 160],
            },
            lcdc: LCDControl::new(),
        }
    }

    /// Retrieves Tile information from the VRAM.
    /// A tile is held in 16 bytes in the VRAM, enough information for 64 pixels (8x8 matrix, 2 bits per pixel).
    /// When selecting tiles from Set #1, the index 0 represents tile -128 (equal to tile 128 from Set #0)
    fn get_tile(&self, set: TileSelector, tile_index: usize) -> Tile {
        // Set1 starts after 128 tiles, or after 16 * 128 = 2048 (0x800) bytes
        let offset = if let TileSelector::Set1 = set { 0x800 } else { 0 };
        let start_addr = (offset + tile_index) * 0x10;
        let end_addr = start_addr + 0x10;

        let mut addr = start_addr;
        let mut pixels = [GBColor::Off; 64];

        // this is basically a for with step 2. Iterates 8 times (two bytes read at a time).
        while addr < end_addr {
            let (low, high) = (self.vram.data[addr], self.vram.data[addr + 1]);

            for i in 0..8 {
                let low_bit = (low >> i) & 0x01;
                let high_bit = (high >> i) & 0x01;

                let pixel_value = GBColor::from_u8(low_bit + high_bit * 2);
                // px 0..7, then 8..15
                let pixel_addr = (addr / 2) * 8 + i;
                pixels[pixel_addr as usize] = pixel_value;
            }

            addr += 2;
        }

        Tile { pixels: pixels }
    }

    pub fn write_vram(&mut self, addr: usize, value: u8) {
        self.vram.data[addr] = value;
    }

    pub fn read_vram(&self, addr: usize) -> u8 {
        self.vram.data[addr]
    }

    pub fn write_oam(&mut self, addr: usize, value: u8) {
        self.vram.oam[addr] = value;
    }

    pub fn read_oam(&self, addr: usize) -> u8 {
        self.vram.oam[addr]
    }

    /// Emulates the GPU.
    /// This function should be called after an instruction is executed by the CPU,
    /// `delta` is the number of cycles passed from the last instruction.
    pub fn emulate(&mut self, delta: u32) {

        self.cycles += delta;

        match self.mode {
            Mode::OAMRead => {
                if self.cycles >= 80 {
                    self.cycles = 0;
                    self.mode = Mode::VRAMRead;
                }
            }
            Mode::VRAMRead => {
                if self.cycles >= 172 {
                    self.cycles = 0;
                    self.mode = Mode::HBlank;

                    // TODO: scanline is done, write it to framebuffer

                }
            }
            Mode::HBlank => {
                if self.cycles >= 204 {
                    self.cycles = 0;
                    self.line += 1;

                    self.mode = if self.line == 143 {
                        Mode::VBlank
                    } else {
                        Mode::OAMRead
                    };
                }
            }
            Mode::VBlank => {
                if self.cycles >= 456 {
                    self.mode = Mode::HBlank;
                    self.line += 1;

                    if self.line > 153 {
                        self.mode = Mode::OAMRead;
                        self.line = 0;
                    }
                }
            }
        }
    }
}

#[test]
fn get_tile_test() {
    let mut gpu = GPU::new();
    // write first line of tile #0 in set #0
    // pixels should be: 0 1 2 3 3 2 1 0
    gpu.write_vram(0, 0b0101_1010u8);
    gpu.write_vram(1, 0b0011_1100u8);

    let tile = gpu.get_tile(TileSelector::Set0, 0);

    assert_eq!(tile.pixels[0], GBColor::Off);
    assert_eq!(tile.pixels[1], GBColor::On33);
    assert_eq!(tile.pixels[2], GBColor::On66);
    assert_eq!(tile.pixels[3], GBColor::On);

    assert_eq!(tile.pixels[4], GBColor::On);
    assert_eq!(tile.pixels[5], GBColor::On66);
    assert_eq!(tile.pixels[6], GBColor::On33);
    assert_eq!(tile.pixels[7], GBColor::Off);

    // rest of the pixels are off
    for i in 8..64 {
        assert_eq!(tile.pixels[i], GBColor::Off);
    }
}<|endoftext|>


<commit_before>// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
// needs-llvm-components: bpf

#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]

#[rustc_builtin_macro]
macro_rules! asm {
    () => {};
}
#[rustc_builtin_macro]
macro_rules! concat {
    () => {};
}
#[rustc_builtin_macro]
macro_rules! stringify {
    () => {};
}

#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}

type ptr = *const u64;

impl Copy for i8 {}
impl Copy for i16 {}
impl Copy for i32 {}
impl Copy for i64 {}
impl Copy for ptr {}

macro_rules! check {
    ($func:ident $ty:ident $class:ident) => {
        #[no_mangle]
        pub unsafe fn $func(x: $ty) -> $ty {
            let y;
            asm!("{} = {}", out($class) y, in($class) x);
            y
        }
    };
}

macro_rules! check_reg {
    ($func:ident $ty:ident $reg:tt) => {
        #[no_mangle]
        pub unsafe fn $func(x: $ty) -> $ty {
            let y;
            asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x);
            y
        }
    };
}

extern "C" {
    fn extern_func();
}

// CHECK-LABEL: sym_fn
// CHECK: #APP
// CHECK: call extern_func
// CHECK: #NO_APP
#[no_mangle]
pub unsafe fn sym_fn() {
    asm!("call {}", sym extern_func);
}

// CHECK-LABEL: reg_i8:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i8 i8 reg);

// CHECK-LABEL: reg_i16:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i16 i16 reg);

// CHECK-LABEL: reg_i32:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i32 i32 reg);

// CHECK-LABEL: reg_i64:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i64 i64 reg);

// CHECK-LABEL: wreg_i8:
// CHECK: #APP
// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
// CHECK: #NO_APP
check!(wreg_i8 i8 wreg);

// CHECK-LABEL: wreg_i16:
// CHECK: #APP
// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
// CHECK: #NO_APP
check!(wreg_i16 i16 wreg);

// CHECK-LABEL: wreg_i32:
// CHECK: #APP
// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
// CHECK: #NO_APP
check!(wreg_i32 i32 wreg);

// CHECK-LABEL: r0_i8:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i8 i8 "r0");

// CHECK-LABEL: r0_i16:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i16 i16 "r0");

// CHECK-LABEL: r0_i32:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i32 i32 "r0");

// CHECK-LABEL: r0_i64:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i64 i64 "r0");

// CHECK-LABEL: w0_i8:
// CHECK: #APP
// CHECK: w0 = w0
// CHECK: #NO_APP
check_reg!(w0_i8 i8 "w0");

// CHECK-LABEL: w0_i16:
// CHECK: #APP
// CHECK: w0 = w0
// CHECK: #NO_APP
check_reg!(w0_i16 i16 "w0");

// CHECK-LABEL: w0_i32:
// CHECK: #APP
// CHECK: w0 = w0
// CHECK: #NO_APP
check_reg!(w0_i32 i32 "w0");
<commit_msg>Rollup merge of #89697 - alessandrod:issue-89689, r=nikic<commit_after>// min-llvm-version: 13.0
// assembly-output: emit-asm
// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
// needs-llvm-components: bpf

#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]

#[rustc_builtin_macro]
macro_rules! asm {
    () => {};
}
#[rustc_builtin_macro]
macro_rules! concat {
    () => {};
}
#[rustc_builtin_macro]
macro_rules! stringify {
    () => {};
}

#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}

type ptr = *const u64;

impl Copy for i8 {}
impl Copy for i16 {}
impl Copy for i32 {}
impl Copy for i64 {}
impl Copy for ptr {}

macro_rules! check {
    ($func:ident $ty:ident $class:ident) => {
        #[no_mangle]
        pub unsafe fn $func(x: $ty) -> $ty {
            let y;
            asm!("{} = {}", out($class) y, in($class) x);
            y
        }
    };
}

macro_rules! check_reg {
    ($func:ident $ty:ident $reg:tt) => {
        #[no_mangle]
        pub unsafe fn $func(x: $ty) -> $ty {
            let y;
            asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x);
            y
        }
    };
}

extern "C" {
    fn extern_func();
}

// CHECK-LABEL: sym_fn
// CHECK: #APP
// CHECK: call extern_func
// CHECK: #NO_APP
#[no_mangle]
pub unsafe fn sym_fn() {
    asm!("call {}", sym extern_func);
}

// CHECK-LABEL: reg_i8:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i8 i8 reg);

// CHECK-LABEL: reg_i16:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i16 i16 reg);

// CHECK-LABEL: reg_i32:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i32 i32 reg);

// CHECK-LABEL: reg_i64:
// CHECK: #APP
// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i64 i64 reg);

// CHECK-LABEL: wreg_i8:
// CHECK: #APP
// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
// CHECK: #NO_APP
check!(wreg_i8 i8 wreg);

// CHECK-LABEL: wreg_i16:
// CHECK: #APP
// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
// CHECK: #NO_APP
check!(wreg_i16 i16 wreg);

// CHECK-LABEL: wreg_i32:
// CHECK: #APP
// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
// CHECK: #NO_APP
check!(wreg_i32 i32 wreg);

// CHECK-LABEL: r0_i8:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i8 i8 "r0");

// CHECK-LABEL: r0_i16:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i16 i16 "r0");

// CHECK-LABEL: r0_i32:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i32 i32 "r0");

// CHECK-LABEL: r0_i64:
// CHECK: #APP
// CHECK: r0 = r0
// CHECK: #NO_APP
check_reg!(r0_i64 i64 "r0");

// CHECK-LABEL: w0_i8:
// CHECK: #APP
// CHECK: w0 = w0
// CHECK: #NO_APP
check_reg!(w0_i8 i8 "w0");

// CHECK-LABEL: w0_i16:
// CHECK: #APP
// CHECK: w0 = w0
// CHECK: #NO_APP
check_reg!(w0_i16 i16 "w0");

// CHECK-LABEL: w0_i32:
// CHECK: #APP
// CHECK: w0 = w0
// CHECK: #NO_APP
check_reg!(w0_i32 i32 "w0");
<|endoftext|>


<commit_before>// revisions: public private
// [private]compile-flags: --document-private-items
// check-pass

// There are 4 cases here:
// 1. public item  -> public type:  no warning
// 2. public item  -> private type: warning, if --document-private-items is not passed
// 3. private item -> public type:  no warning
// 4. private item -> private type: no warning
// All 4 cases are tested with and without --document-private-items.
//
// Case 4 without --document-private-items is the one described in issue #74134.

struct PrivateType;
pub struct PublicType;

pub struct Public {
    /// [`PublicType`]
    /// [`PrivateType`]
    //[public]~^ WARNING `[PrivateType]` public documentation for `public_item` links to a private item
    pub public_item: u32,

    /// [`PublicType`]
    /// [`PrivateType`]
    private_item: u32,
}
<commit_msg>test: rustdoc-ui: Expand issue-74134 to cover types in a private module<commit_after>// revisions: public private
// [private]compile-flags: --document-private-items
// check-pass

// There are 4 cases here:
// 1. public item  -> public type:  no warning
// 2. public item  -> private type: warning, if --document-private-items is not passed
// 3. private item -> public type:  no warning
// 4. private item -> private type: no warning
// All 4 cases are tested with and without --document-private-items.
//
// Case 4 without --document-private-items is the one described in issue #74134.

struct PrivateType;
pub struct PublicType;

pub struct Public {
    /// [`PublicType`]
    /// [`PrivateType`]
    //[public]~^ WARNING `[PrivateType]` public documentation for `public_item` links to a private item
    pub public_item: u32,

    /// [`PublicType`]
    /// [`PrivateType`]
    private_item: u32,
}

// The following cases are identical to the ones above, except that they are in a private
// module. Thus they all fall into cases 3 and 4 and should not produce a warning.

mod private {
    pub struct Public {
        /// [`super::PublicType`]
        /// [`super::PrivateType`]
        pub public_item: u32,

        /// [`super::PublicType`]
        /// [`super::PrivateType`]
        private_item: u32,
    }
}
<|endoftext|>