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

use libc::{self, c_char, c_int, c_short, c_uint, c_ushort, c_void, size_t, sockaddr, sockaddr_un, socklen_t};
use libc::{ssize_t};
use std::ffi::{CStr, CString};
use std::io::Error;
use std::iter;
use std::mem;
use std::ptr;

pub fn channel() -> Result<(UnixSender, UnixReceiver),c_int> {
    let mut results = [0, 0];
    unsafe {
        if socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut results[0]) >= 0 {
            Ok((UnixSender::from_fd(results[0]), UnixReceiver::from_fd(results[1])))
        } else {
            Err(Error::last_os_error().raw_os_error().unwrap())
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixReceiver {
    fd: c_int,
}

impl Drop for UnixReceiver {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixReceiver {
    fn from_fd(fd: c_int) -> UnixReceiver {
        UnixReceiver {
            fd: fd,
        }
    }

    pub fn consume(&self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut length_data: [usize; 2] = [0, 0];
            let result = libc::recv(self.fd,
                                    &mut length_data[0] as *mut _ as *mut c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    MSG_WAITALL);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let [data_length, channel_length] = length_data;
            let cmsg_length = mem::size_of::<cmsghdr>() + channel_length * mem::size_of::<c_int>();
            let cmsg_buffer: *mut cmsghdr = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;

            let mut data_buffer: Vec<u8> = iter::repeat(0).take(data_length).collect();
            let mut iovec = iovec {
                iov_base: &mut data_buffer[0] as *mut _ as *mut i8,
                iov_len: data_length as size_t,
            };

            let mut msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = recvmsg(self.fd, &mut msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_fds = cmsg_buffer.offset(1) as *const u8 as *const c_int;
            let channels = (0..channel_length).map(|index| {
                UnknownUnixChannel::from_fd(*cmsg_fds.offset(index as isize))
            }).collect();

            Ok((data_buffer, channels))
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixSender {
    fd: c_int,
}

impl Drop for UnixSender {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl Clone for UnixSender {
    fn clone(&self) -> UnixSender {
        unsafe {
            UnixSender {
                fd: libc::dup(self.fd)
            }
        }
    }
}

impl UnixSender {
    fn from_fd(fd: c_int) -> UnixSender {
        UnixSender {
            fd: fd,
        }
    }

    pub fn send(&self, data: &[u8], channels: Vec<UnixChannel>) -> Result<(),c_int> {
        unsafe {
            let length_data: [usize; 2] = [data.len(), channels.len()];
            let result = libc::send(self.fd,
                                    &length_data[0] as *const _ as *const c_void,
                                    mem::size_of::<[usize; 2]>() as u64,
                                    0);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_length = mem::size_of::<cmsghdr>() + channels.len() * mem::size_of::<c_int>();
            let cmsg_buffer = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;
            (*cmsg_buffer).cmsg_len = cmsg_length as size_t;
            (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
            (*cmsg_buffer).cmsg_type = SCM_RIGHTS;

            let mut fds = Vec::new();
            for channel in channels.into_iter() {
                fds.push(channel.fd());
                mem::forget(channel);
            }
            ptr::copy_nonoverlapping(fds.as_ptr(),
                                     cmsg_buffer.offset(1) as *mut _ as *mut c_int,
                                     fds.len());

            let mut iovec = iovec {
                iov_base: data.as_ptr() as *const i8 as *mut i8,
                iov_len: data.len() as size_t,
            };

            let msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = sendmsg(self.fd, &msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);

            if result > 0 {
                Ok(())
            } else {
                Err(Error::last_os_error().raw_os_error().unwrap())
            }
        }
    }

    pub fn connect(name: String) -> Result<UnixSender,c_int> {
        let name = CString::new(name).unwrap();
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut sockaddr = sockaddr_un {
                sun_family: libc::AF_UNIX as u16,
                sun_path: [ 0; 108 ],
            };
            libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                          name.as_ptr(),
                          sockaddr.sun_path.len() as size_t);

            let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
            if libc::connect(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok(UnixSender {
                fd: fd,
            })
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum UnixChannel {
    Sender(UnixSender),
    Receiver(UnixReceiver),
}

impl UnixChannel {
    fn fd(&self) -> c_int {
        match *self {
            UnixChannel::Sender(ref sender) => sender.fd,
            UnixChannel::Receiver(ref receiver) => receiver.fd,
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnknownUnixChannel {
    fd: c_int,
}

impl Drop for UnknownUnixChannel {
    fn drop(&mut self) {
        unsafe {
            debug_assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnknownUnixChannel {
    fn from_fd(fd: c_int) -> UnknownUnixChannel {
        UnknownUnixChannel {
            fd: fd,
        }
    }

    pub fn to_sender(&mut self) -> UnixSender {
        unsafe {
            UnixSender::from_fd(libc::dup(self.fd))
        }
    }

    pub fn to_receiver(&mut self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }
}

pub struct UnixOneShotServer {
    fd: c_int,
}

impl Drop for UnixOneShotServer {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixOneShotServer {
    pub fn new() -> Result<(UnixOneShotServer, String),c_int> {
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut path: Vec<u8>;
            loop {
                let path_string = CString::new(b"/tmp/rust-ipc-socket.XXXXXX" as &[u8]).unwrap();
                path = path_string.as_bytes().iter().cloned().collect();
                if mktemp(path.as_mut_ptr() as *mut c_char) == ptr::null_mut() {
                    return Err(Error::last_os_error().raw_os_error().unwrap())
                }

                let mut sockaddr = sockaddr_un {
                    sun_family: libc::AF_UNIX as c_ushort,
                    sun_path: [ 0; 108 ],
                };
                libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                              path.as_ptr() as *const c_char,
                              sockaddr.sun_path.len() as size_t);

                let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
                if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) == 0 {
                    break
                }

                let errno = Error::last_os_error().raw_os_error().unwrap();
                if errno != libc::EINVAL {
                    return Err(errno)
                }
            }

            if libc::listen(fd, 10) != 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok((UnixOneShotServer {
                fd: fd,
            }, String::from_utf8(CStr::from_ptr(path.as_ptr() as *const c_char).to_bytes().to_owned()).unwrap()))
        }
    }

    pub fn accept(self) -> Result<(UnixReceiver, Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut sockaddr = mem::uninitialized();
            let mut sockaddr_len = mem::uninitialized();
            let client_fd = libc::accept(self.fd, &mut sockaddr, &mut sockaddr_len);
            if client_fd < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let receiver = UnixReceiver {
                fd: client_fd,
            };
            let (data, channels) = try!(receiver.recv());
            Ok((receiver, data, channels))
        }
    }
}

// FFI stuff follows:

const MSG_WAITALL: c_int = 0x100;
const SCM_RIGHTS: c_int = 0x01;

extern {
    fn mktemp(template: *mut c_char) -> *mut c_char;
    fn recvmsg(socket: c_int, message: *mut msghdr, flags: c_int) -> ssize_t;
    fn sendmsg(socket: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
    fn socketpair(domain: c_int, socket_type: c_int, protocol: c_int, sv: *mut c_int) -> c_int;
}

#[repr(C)]
struct msghdr {
    msg_name: *mut c_void,
    msg_namelen: socklen_t,
    msg_iov: *mut iovec,
    msg_iovlen: size_t,
    msg_control: *mut c_void,
    msg_controllen: size_t,
    msg_flags: c_int,
}

#[repr(C)]
struct iovec {
    iov_base: *mut c_char,
    iov_len: size_t,
}

#[repr(C)]
struct cmsghdr {
    cmsg_len: size_t,
    cmsg_level: c_int,
    cmsg_type: c_int,
}

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

use libc::{self, c_char, c_int, c_short, c_uint, c_ushort, c_void, size_t, sockaddr, sockaddr_un, socklen_t};
use libc::{ssize_t};
use std::ffi::{CStr, CString};
use std::io::Error;
use std::iter;
use std::mem;
use std::ptr;

pub fn channel() -> Result<(UnixSender, UnixReceiver),c_int> {
    let mut results = [0, 0];
    unsafe {
        if socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut results[0]) >= 0 {
            Ok((UnixSender::from_fd(results[0]), UnixReceiver::from_fd(results[1])))
        } else {
            Err(Error::last_os_error().raw_os_error().unwrap())
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixReceiver {
    fd: c_int,
}

impl Drop for UnixReceiver {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixReceiver {
    fn from_fd(fd: c_int) -> UnixReceiver {
        UnixReceiver {
            fd: fd,
        }
    }

    pub fn consume(&self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut length_data: [usize; 2] = [0, 0];
            let result = libc::recv(self.fd,
                                    &mut length_data[0] as *mut _ as *mut c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    MSG_WAITALL);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let [data_length, channel_length] = length_data;
            let cmsg_length = mem::size_of::<cmsghdr>() + channel_length * mem::size_of::<c_int>();
            let cmsg_buffer: *mut cmsghdr = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;

            let mut data_buffer: Vec<u8> = iter::repeat(0).take(data_length).collect();
            let mut iovec = iovec {
                iov_base: &mut data_buffer[0] as *mut _ as *mut i8,
                iov_len: data_length as size_t,
            };

            let mut msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = recvmsg(self.fd, &mut msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_fds = cmsg_buffer.offset(1) as *const u8 as *const c_int;
            let channels = (0..channel_length).map(|index| {
                UnknownUnixChannel::from_fd(*cmsg_fds.offset(index as isize))
            }).collect();

            Ok((data_buffer, channels))
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixSender {
    fd: c_int,
}

impl Drop for UnixSender {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl Clone for UnixSender {
    fn clone(&self) -> UnixSender {
        unsafe {
            UnixSender {
                fd: libc::dup(self.fd)
            }
        }
    }
}

impl UnixSender {
    fn from_fd(fd: c_int) -> UnixSender {
        UnixSender {
            fd: fd,
        }
    }

    pub fn send(&self, data: &[u8], channels: Vec<UnixChannel>) -> Result<(),c_int> {
        unsafe {
            let length_data: [usize; 2] = [data.len(), channels.len()];
            let result = libc::send(self.fd,
                                    &length_data[0] as *const _ as *const c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    0);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_length = mem::size_of::<cmsghdr>() + channels.len() * mem::size_of::<c_int>();
            let cmsg_buffer = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;
            (*cmsg_buffer).cmsg_len = cmsg_length as size_t;
            (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
            (*cmsg_buffer).cmsg_type = SCM_RIGHTS;

            let mut fds = Vec::new();
            for channel in channels.into_iter() {
                fds.push(channel.fd());
                mem::forget(channel);
            }
            ptr::copy_nonoverlapping(fds.as_ptr(),
                                     cmsg_buffer.offset(1) as *mut _ as *mut c_int,
                                     fds.len());

            let mut iovec = iovec {
                iov_base: data.as_ptr() as *const i8 as *mut i8,
                iov_len: data.len() as size_t,
            };

            let msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = sendmsg(self.fd, &msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);

            if result > 0 {
                Ok(())
            } else {
                Err(Error::last_os_error().raw_os_error().unwrap())
            }
        }
    }

    pub fn connect(name: String) -> Result<UnixSender,c_int> {
        let name = CString::new(name).unwrap();
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut sockaddr = sockaddr_un {
                sun_family: libc::AF_UNIX as u16,
                sun_path: [ 0; 108 ],
            };
            libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                          name.as_ptr(),
                          sockaddr.sun_path.len() as size_t);

            let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
            if libc::connect(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok(UnixSender {
                fd: fd,
            })
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum UnixChannel {
    Sender(UnixSender),
    Receiver(UnixReceiver),
}

impl UnixChannel {
    fn fd(&self) -> c_int {
        match *self {
            UnixChannel::Sender(ref sender) => sender.fd,
            UnixChannel::Receiver(ref receiver) => receiver.fd,
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnknownUnixChannel {
    fd: c_int,
}

impl Drop for UnknownUnixChannel {
    fn drop(&mut self) {
        unsafe {
            debug_assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnknownUnixChannel {
    fn from_fd(fd: c_int) -> UnknownUnixChannel {
        UnknownUnixChannel {
            fd: fd,
        }
    }

    pub fn to_sender(&mut self) -> UnixSender {
        unsafe {
            UnixSender::from_fd(libc::dup(self.fd))
        }
    }

    pub fn to_receiver(&mut self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }
}

pub struct UnixOneShotServer {
    fd: c_int,
}

impl Drop for UnixOneShotServer {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixOneShotServer {
    pub fn new() -> Result<(UnixOneShotServer, String),c_int> {
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut path: Vec<u8>;
            loop {
                let path_string = CString::new(b"/tmp/rust-ipc-socket.XXXXXX" as &[u8]).unwrap();
                path = path_string.as_bytes().iter().cloned().collect();
                if mktemp(path.as_mut_ptr() as *mut c_char) == ptr::null_mut() {
                    return Err(Error::last_os_error().raw_os_error().unwrap())
                }

                let mut sockaddr = sockaddr_un {
                    sun_family: libc::AF_UNIX as c_ushort,
                    sun_path: [ 0; 108 ],
                };
                libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                              path.as_ptr() as *const c_char,
                              sockaddr.sun_path.len() as size_t);

                let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
                if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) == 0 {
                    break
                }

                let errno = Error::last_os_error().raw_os_error().unwrap();
                if errno != libc::EINVAL {
                    return Err(errno)
                }
            }

            if libc::listen(fd, 10) != 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok((UnixOneShotServer {
                fd: fd,
            }, String::from_utf8(CStr::from_ptr(path.as_ptr() as *const c_char).to_bytes().to_owned()).unwrap()))
        }
    }

    pub fn accept(self) -> Result<(UnixReceiver, Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut sockaddr = mem::uninitialized();
            let mut sockaddr_len = mem::uninitialized();
            let client_fd = libc::accept(self.fd, &mut sockaddr, &mut sockaddr_len);
            if client_fd < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let receiver = UnixReceiver {
                fd: client_fd,
            };
            let (data, channels) = try!(receiver.recv());
            Ok((receiver, data, channels))
        }
    }
}

// FFI stuff follows:

const MSG_WAITALL: c_int = 0x100;
const SCM_RIGHTS: c_int = 0x01;

extern {
    fn mktemp(template: *mut c_char) -> *mut c_char;
    fn recvmsg(socket: c_int, message: *mut msghdr, flags: c_int) -> ssize_t;
    fn sendmsg(socket: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
    fn socketpair(domain: c_int, socket_type: c_int, protocol: c_int, sv: *mut c_int) -> c_int;
}

#[repr(C)]
struct msghdr {
    msg_name: *mut c_void,
    msg_namelen: socklen_t,
    msg_iov: *mut iovec,
    msg_iovlen: size_t,
    msg_control: *mut c_void,
    msg_controllen: size_t,
    msg_flags: c_int,
}

#[repr(C)]
struct iovec {
    iov_base: *mut c_char,
    iov_len: size_t,
}

#[repr(C)]
struct cmsghdr {
    cmsg_len: size_t,
    cmsg_level: c_int,
    cmsg_type: c_int,
}

<|endoftext|>


<commit_before>extern crate hyper;

use std::io::Read;
use std::sync::Mutex;

use self::hyper::net::Fresh;
use self::hyper::client::Client;
use self::hyper::header::Connection;
use self::hyper::header::Host;
use self::hyper::server::Handler;
use self::hyper::server::Request;
use self::hyper::server::Response;

use http::app_manager::AppManager;

pub struct Dispatcher {
    pub app_manager: Mutex<AppManager>,
}

impl Dispatcher {
    pub fn new(app_manager: AppManager) -> Dispatcher {
        Dispatcher {
            app_manager: Mutex::new(app_manager),
        }
    }

    fn ensure_app_running(&self, request: &Request) -> u16 {
        let host = &request.headers.get::<Host>().unwrap().hostname;
        let host_parts = host.split(".").collect::<Vec<_>>();
        let app_name = host_parts.first().unwrap();

        let mut app_manager = self.app_manager.lock().unwrap();

        app_manager.ensure_app_running(&app_name)
    }
}

impl Handler for Dispatcher {
    fn handle(&self, request: Request, response: Response<Fresh>) {
        let port = self.ensure_app_running(&request);

        let url = format!("http://localhost:{}", port);

        let client = Client::new();

        let mut app_response = client.get(&url)
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        app_response.read_to_string(&mut body).unwrap();

        response.send(&body.into_bytes()).unwrap();
    }
}
<commit_msg>refactor: Break method in two to better separate concerns<commit_after>extern crate hyper;

use std::io::Read;
use std::sync::Mutex;

use self::hyper::net::Fresh;
use self::hyper::client::Client;
use self::hyper::header::Connection;
use self::hyper::header::Host;
use self::hyper::server::Handler;
use self::hyper::server::Request;
use self::hyper::server::Response;

use http::app_manager::AppManager;

pub struct Dispatcher {
    pub app_manager: Mutex<AppManager>,
}

impl Dispatcher {
    pub fn new(app_manager: AppManager) -> Dispatcher {
        Dispatcher {
            app_manager: Mutex::new(app_manager),
        }
    }

    fn extract_app_name<'a>(&'a self, request: &'a Request) -> &str {
        let host = &request.headers.get::<Host>().unwrap().hostname;
        let host_parts = host.split(".").collect::<Vec<_>>();

        host_parts.first().unwrap()
    }

    fn ensure_app_running(&self, app_name: &str) -> u16 {
        let mut app_manager = self.app_manager.lock().unwrap();

        app_manager.ensure_app_running(&app_name)
    }
}

impl Handler for Dispatcher {
    fn handle(&self, request: Request, response: Response<Fresh>) {
        let app_name = self.extract_app_name(&request);
        let port = self.ensure_app_running(app_name);

        let url = format!("http://localhost:{}", port);

        let client = Client::new();

        let mut app_response = client.get(&url)
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        app_response.read_to_string(&mut body).unwrap();

        response.send(&body.into_bytes()).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Codegen `extern "platform-intrinsic"` intrinsics.

use super::*;
use crate::prelude::*;

pub(super) fn codegen_simd_intrinsic_call<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    instance: Instance<'tcx>,
    args: &[mir::Operand<'tcx>],
    ret: CPlace<'tcx>,
    span: Span,
) {
    let def_id = instance.def_id();
    let substs = instance.substs;

    let intrinsic = fx.tcx.item_name(def_id).as_str();
    let intrinsic = &intrinsic[..];

    intrinsic_match! {
        fx, intrinsic, substs, args,
        _ => {
            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
        };

        simd_cast, (c a) {
            validate_simd_type!(fx, intrinsic, span, a.layout().ty);
            simd_for_each_lane(fx, a, ret, |fx, lane_layout, ret_lane_layout, lane| {
                let ret_lane_ty = fx.clif_type(ret_lane_layout.ty).unwrap();

                let from_signed = type_sign(lane_layout.ty);
                let to_signed = type_sign(ret_lane_layout.ty);

                let ret_lane = clif_int_or_float_cast(fx, lane, from_signed, ret_lane_ty, to_signed);
                CValue::by_val(ret_lane, ret_lane_layout)
            });
        };

        // FIXME support float comparisons
        simd_eq, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, Equal(x, y) -> ret);
        };
        simd_ne, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, NotEqual(x, y) -> ret);
        };
        simd_lt, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedLessThan|SignedLessThan(x, y) -> ret);
        };
        simd_le, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret);
        };
        simd_gt, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret);
        };
        simd_ge, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret);
        };

        // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
        _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);

            let n: u16 = intrinsic["simd_shuffle".len()..].parse().unwrap();

            assert_eq!(x.layout(), y.layout());
            let layout = x.layout();

            let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
            let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());

            assert_eq!(lane_type, ret_lane_type);
            assert_eq!(n, ret_lane_count);

            let total_len = lane_count * 2;

            let indexes = {
                use rustc_middle::mir::interpret::*;
                let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");

                let idx_bytes = match idx_const.val {
                    ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => {
                        let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
                        let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */);
                        alloc.get_bytes(fx, ptr, size).unwrap()
                    }
                    _ => unreachable!("{:?}", idx_const),
                };

                (0..ret_lane_count).map(|i| {
                    let i = usize::try_from(i).unwrap();
                    let idx = rustc_middle::mir::interpret::read_target_uint(
                        fx.tcx.data_layout.endian,
                        &idx_bytes[4*i.. 4*i + 4],
                    ).expect("read_target_uint");
                    u16::try_from(idx).expect("try_from u32")
                }).collect::<Vec<u16>>()
            };

            for &idx in &indexes {
                assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
            }

            for (out_idx, in_idx) in indexes.into_iter().enumerate() {
                let in_lane = if in_idx < lane_count {
                    x.value_field(fx, mir::Field::new(in_idx.try_into().unwrap()))
                } else {
                    y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap()))
                };
                let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
                out_lane.write_cvalue(fx, in_lane);
            }
        };

        simd_insert, (c base, o idx, c val) {
            // FIXME validate
            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
                idx_const
            } else {
                fx.tcx.sess.span_warn(
                    fx.mir.span,
                    "`#[rustc_arg_required_const(..)]` is not yet supported. Calling this function will panic.",
                );
                crate::trap::trap_unimplemented(fx, "`#[rustc_arg_required_const(..)]` is not yet supported.");
                return;
            };

            let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
            let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout());
            if idx >= lane_count.into() {
                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
            }

            ret.write_cvalue(fx, base);
            let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap()));
            ret_lane.write_cvalue(fx, val);
        };

        simd_extract, (c v, o idx) {
            validate_simd_type!(fx, intrinsic, span, v.layout().ty);
            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
                idx_const
            } else {
                fx.tcx.sess.span_warn(
                    fx.mir.span,
                    "`#[rustc_arg_required_const(..)]` is not yet supported. Calling this function will panic.",
                );
                let val = crate::trap::trap_unimplemented_ret_value(fx, ret.layout(), "`#[rustc_arg_required_const(..)]` is not yet supported.");
                ret.write_cvalue(fx, val);
                return;
            };

            let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
            let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
            if idx >= lane_count.into() {
                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
            }

            let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
            ret.write_cvalue(fx, ret_lane);
        };

        simd_add, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, iadd|fadd(x, y) -> ret);
        };
        simd_sub, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, isub|fsub(x, y) -> ret);
        };
        simd_mul, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, imul|fmul(x, y) -> ret);
        };
        simd_div, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, udiv|sdiv|fdiv(x, y) -> ret);
        };
        simd_shl, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, ishl(x, y) -> ret);
        };
        simd_shr, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, ushr|sshr(x, y) -> ret);
        };
        simd_and, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, band(x, y) -> ret);
        };
        simd_or, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, bor(x, y) -> ret);
        };
        simd_xor, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, bxor(x, y) -> ret);
        };

        simd_fma, (c a, c b, c c) {
            validate_simd_type!(fx, intrinsic, span, a.layout().ty);
            assert_eq!(a.layout(), b.layout());
            assert_eq!(a.layout(), c.layout());
            let layout = a.layout();

            let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
            let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
            assert_eq!(lane_count, ret_lane_count);

            for lane in 0..lane_count {
                let lane = mir::Field::new(lane.try_into().unwrap());
                let a_lane = a.value_field(fx, lane).load_scalar(fx);
                let b_lane = b.value_field(fx, lane).load_scalar(fx);
                let c_lane = c.value_field(fx, lane).load_scalar(fx);

                let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
                let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);

                ret.place_field(fx, lane).write_cvalue(fx, res_lane);
            }
        };

        simd_fmin, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_flt_binop!(fx, fmin(x, y) -> ret);
        };
        simd_fmax, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_flt_binop!(fx, fmax(x, y) -> ret);
        };

        // simd_fabs
        // simd_saturating_add
        // simd_bitmask
        // simd_select
        // simd_reduce_add_{,un}ordered
        // simd_rem
    }
}
<commit_msg>Error on non-constant simd_insert/simd_extract index<commit_after>//! Codegen `extern "platform-intrinsic"` intrinsics.

use super::*;
use crate::prelude::*;

pub(super) fn codegen_simd_intrinsic_call<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    instance: Instance<'tcx>,
    args: &[mir::Operand<'tcx>],
    ret: CPlace<'tcx>,
    span: Span,
) {
    let def_id = instance.def_id();
    let substs = instance.substs;

    let intrinsic = fx.tcx.item_name(def_id).as_str();
    let intrinsic = &intrinsic[..];

    intrinsic_match! {
        fx, intrinsic, substs, args,
        _ => {
            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
        };

        simd_cast, (c a) {
            validate_simd_type!(fx, intrinsic, span, a.layout().ty);
            simd_for_each_lane(fx, a, ret, |fx, lane_layout, ret_lane_layout, lane| {
                let ret_lane_ty = fx.clif_type(ret_lane_layout.ty).unwrap();

                let from_signed = type_sign(lane_layout.ty);
                let to_signed = type_sign(ret_lane_layout.ty);

                let ret_lane = clif_int_or_float_cast(fx, lane, from_signed, ret_lane_ty, to_signed);
                CValue::by_val(ret_lane, ret_lane_layout)
            });
        };

        // FIXME support float comparisons
        simd_eq, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, Equal(x, y) -> ret);
        };
        simd_ne, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, NotEqual(x, y) -> ret);
        };
        simd_lt, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedLessThan|SignedLessThan(x, y) -> ret);
        };
        simd_le, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret);
        };
        simd_gt, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret);
        };
        simd_ge, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_cmp!(fx, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret);
        };

        // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
        _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);

            let n: u16 = intrinsic["simd_shuffle".len()..].parse().unwrap();

            assert_eq!(x.layout(), y.layout());
            let layout = x.layout();

            let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
            let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());

            assert_eq!(lane_type, ret_lane_type);
            assert_eq!(n, ret_lane_count);

            let total_len = lane_count * 2;

            let indexes = {
                use rustc_middle::mir::interpret::*;
                let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");

                let idx_bytes = match idx_const.val {
                    ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => {
                        let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
                        let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */);
                        alloc.get_bytes(fx, ptr, size).unwrap()
                    }
                    _ => unreachable!("{:?}", idx_const),
                };

                (0..ret_lane_count).map(|i| {
                    let i = usize::try_from(i).unwrap();
                    let idx = rustc_middle::mir::interpret::read_target_uint(
                        fx.tcx.data_layout.endian,
                        &idx_bytes[4*i.. 4*i + 4],
                    ).expect("read_target_uint");
                    u16::try_from(idx).expect("try_from u32")
                }).collect::<Vec<u16>>()
            };

            for &idx in &indexes {
                assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
            }

            for (out_idx, in_idx) in indexes.into_iter().enumerate() {
                let in_lane = if in_idx < lane_count {
                    x.value_field(fx, mir::Field::new(in_idx.try_into().unwrap()))
                } else {
                    y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap()))
                };
                let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
                out_lane.write_cvalue(fx, in_lane);
            }
        };

        simd_insert, (c base, o idx, c val) {
            // FIXME validate
            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
                idx_const
            } else {
                fx.tcx.sess.span_fatal(
                    span,
                    "Index argument for `simd_insert` is not a constant",
                );
            };

            let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
            let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout());
            if idx >= lane_count.into() {
                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
            }

            ret.write_cvalue(fx, base);
            let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap()));
            ret_lane.write_cvalue(fx, val);
        };

        simd_extract, (c v, o idx) {
            validate_simd_type!(fx, intrinsic, span, v.layout().ty);
            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
                idx_const
            } else {
                fx.tcx.sess.span_fatal(
                    span,
                    "Index argument for `simd_extract` is not a constant",
                );
            };

            let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
            let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
            if idx >= lane_count.into() {
                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
            }

            let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
            ret.write_cvalue(fx, ret_lane);
        };

        simd_add, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, iadd|fadd(x, y) -> ret);
        };
        simd_sub, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, isub|fsub(x, y) -> ret);
        };
        simd_mul, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, imul|fmul(x, y) -> ret);
        };
        simd_div, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_flt_binop!(fx, udiv|sdiv|fdiv(x, y) -> ret);
        };
        simd_shl, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, ishl(x, y) -> ret);
        };
        simd_shr, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, ushr|sshr(x, y) -> ret);
        };
        simd_and, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, band(x, y) -> ret);
        };
        simd_or, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, bor(x, y) -> ret);
        };
        simd_xor, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_int_binop!(fx, bxor(x, y) -> ret);
        };

        simd_fma, (c a, c b, c c) {
            validate_simd_type!(fx, intrinsic, span, a.layout().ty);
            assert_eq!(a.layout(), b.layout());
            assert_eq!(a.layout(), c.layout());
            let layout = a.layout();

            let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
            let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
            assert_eq!(lane_count, ret_lane_count);

            for lane in 0..lane_count {
                let lane = mir::Field::new(lane.try_into().unwrap());
                let a_lane = a.value_field(fx, lane).load_scalar(fx);
                let b_lane = b.value_field(fx, lane).load_scalar(fx);
                let c_lane = c.value_field(fx, lane).load_scalar(fx);

                let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
                let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);

                ret.place_field(fx, lane).write_cvalue(fx, res_lane);
            }
        };

        simd_fmin, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_flt_binop!(fx, fmin(x, y) -> ret);
        };
        simd_fmax, (c x, c y) {
            validate_simd_type!(fx, intrinsic, span, x.layout().ty);
            simd_flt_binop!(fx, fmax(x, y) -> ret);
        };

        // simd_fabs
        // simd_saturating_add
        // simd_bitmask
        // simd_select
        // simd_reduce_add_{,un}ordered
        // simd_rem
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use yaml_rust::Yaml;
use tmux;

#[cfg(test)] use yaml_rust::{YamlLoader};

#[derive(Debug)]
pub struct Command {
    //commands: Vec<Command>,
    key: String,
    value: String
}

pub fn main(yaml_string: &Vec<Yaml>) -> Vec<Command> {
    let mut commands: Vec<Command> = vec!();
    //println!("{:?}", yaml_string);

    fn yaml_match(y: &Yaml) {
        match y {
            &Yaml::Array(ref v) => {
                for x in v {
                    yaml_match(x);
                }
            },
            &Yaml::Hash(ref h) => {
                for (k, v) in h {
                    println!("hash: {:?}:", k);
                    yaml_match(v);
                }
            },
            _ => print!("{:?}", y)
        };
    };

    for doc in yaml_string {
        for window in doc["windows"].as_vec().unwrap() {
            match window {
                &Yaml::Hash(ref h)  => {
                    for (k, v) in h {
                        commands.push(Command{key: "window".to_string(), value: k.as_str().unwrap().to_string()})
                    }
                },
                &Yaml::String(ref s) => {
                    commands.push(Command{key: "window".to_string(), value: s.as_str().to_string()})
                },
                _ => panic!("nope")
            };
        };
    };

    println!("{:?}", commands);
    commands
}
<commit_msg>Begin writing test cases for validation and edge case finding.<commit_after>use std::collections::BTreeMap;
use yaml_rust::Yaml;
use tmux;

#[cfg(test)] use yaml_rust::{YamlLoader};

#[derive(Debug)]
pub struct Command {
    //commands: Vec<Command>,
    key: String,
    value: String
}

pub fn main(yaml_string: &Vec<Yaml>) -> Vec<Command> {
    let mut commands: Vec<Command> = vec!();
    //println!("{:?}", yaml_string);

    fn yaml_match(y: &Yaml) {
        match y {
            &Yaml::Array(ref v) => {
                for x in v {
                    yaml_match(x);
                }
            },
            &Yaml::Hash(ref h) => {
                for (k, v) in h {
                    println!("hash: {:?}:", k);
                    yaml_match(v);
                }
            },
            _ => print!("{:?}", y)
        };
    };

    for doc in yaml_string {
        for window in doc["windows"].as_vec().unwrap() {
            match window {
                &Yaml::Hash(ref h)  => {
                    for (k, v) in h {
                        commands.push(Command{key: "window".to_string(), value: k.as_str().unwrap().to_string()})
                    }
                },
                &Yaml::String(ref s) => {
                    commands.push(Command{key: "window".to_string(), value: s.as_str().to_string()})
                },
                _ => panic!("nope")
            };
        };
    };

    println!("{:?}", commands);
    commands
}

#[test]
pub fn windows_as_array() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let commands = main(&yaml);
    assert_eq!(commands.len(), 3)
}

#[test]
pub fn windows_as_list() {
    let s = "---
windows:
  - cargo: ''
  - vim: ''
  - git: ''
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let commands = main(&yaml);
    assert_eq!(commands.len(), 3)
}
<|endoftext|>


<commit_before>//! Tests for the registry

use std::sync::{mpsc, Arc, Mutex, Condvar};
use std::time::Duration;
use std::thread;

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson};

use registry;
use registry::{AccessFlags, get_struct};

lazy_static! {
    static ref ACCESS_PAIR: Arc<(Mutex<bool>, Condvar)>
        = Arc::new((Mutex::new(false), Condvar::new()));
}

// Constants for use with registry-accessing tests

pub const BOOL: bool = true;
pub const U64: u64 = 42;
pub const I64: i64 = -1;
pub const F64: f64 = 21.5;

pub const TEXT: &'static str = "Hello way-cooler";
pub const POINT: Point = Point { x: 12, y: 12 };

pub const READONLY: &'static str = "read only text";
pub const WRITEONLY: &'static str = "write only text";
pub const NO_PERMS: &'static str = "<look ma no perms>";

pub const PROP_GET_RESULT: &'static str = "get property";

pub fn get_prop() -> Json {
    PROP_GET_RESULT.to_json()
}

pub fn set_prop(json: Json) {
    println!("set_prop: got {:?}", json);
}

pub fn command() {
    println!("command executed!");
}

/// [0, 1, 2]
pub fn u64s() -> Vec<Json> {
    vec![Json::U64(0), Json::U64(1), Json::U64(2)]
}

/// Wait for the registry to initialize
pub fn wait_for_registry() {
    // First star for lazy static, second for Arc
    let &(ref lock, ref cond) = &**ACCESS_PAIR;
    let mut started = lock.lock().expect("Unable to lock ACCESS_PAIR lock!");
    while !*started {
        started = cond.wait(started)
            .expect("Oh boy, I can't wait for the registry to start!");
    }
}

json_convertible! {
    /// Has an x and y field
    #[derive(Debug, Clone, Eq, PartialEq)]
    struct Point {
        x: i32,
        y: i32
    }
}

unsafe impl Sync for Point {}

impl Point {
    /// Creates a new point with the given coordinates
    pub fn new(x: i32, y: i32) -> Point {
        Point { x: x, y: y }
    }

    /// A point at 0, 0
    pub fn origin() -> Point {
        Point { x: 0, y: 0 }
    }
}

const ERR: &'static str = "Generic registry test error!";

#[test]
fn add_keys() {
    let values = vec![
        ("bool", AccessFlags::all(), BOOL.to_json()),
        ("u64", AccessFlags::all(), U64.to_json()),
        ("i64", AccessFlags::all(), I64.to_json()),
        ("f64", AccessFlags::all(), F64.to_json()),
        ("text", AccessFlags::all(), TEXT.to_json()),
        ("point", AccessFlags::all(), POINT.to_json()),
        ("null", AccessFlags::all(), Json::Null),
        ("u64s", AccessFlags::all(), Json::Array(u64s())),

        ("readonly", AccessFlags::READ(), READONLY.to_json()),
        ("writeonly", AccessFlags::WRITE(), WRITEONLY.to_json()),
    ];

    for (name, flags, json) in values.into_iter() {
        registry::set_json(name.to_string(), flags, json)
            .expect("Unable to initialize objects in registry");
    }

    registry::set_command("command".to_string(), Arc::new(command))
        .expect("Unable to initialize command in registry");

    registry::set_property_field("prop".to_string(),
                                 Some(Arc::new(get_prop)),
                                 Some(Arc::new(set_prop)))
        .expect("Unable to initialize property in registry");

    registry::set_property_field("prop_read".to_string(),
                                 Some(Arc::new(get_prop)),
                                 None)
        .expect("Unable to initialize property in registry");
    registry::set_property_field("prop_write".to_string(),
                                 None,
                                 Some(Arc::new(set_prop)))
        .expect("Unable to initialize property in registry");

    // Allow waiting threads to continue
    let &(ref lock, ref cond) = &**ACCESS_PAIR;
    let mut started = lock.lock().expect("Couldn't unlock threads");
    *started = true;
    cond.notify_all();
}

#[test]
fn contains_keys() {
    wait_for_registry();

    let keys = [
        "bool", "u64", "i64", "f64", "null", "text", "point",
        "u64s", "readonly", "writeonly", "prop",
        "prop_read", "prop_write", "command",
    ];
    for key in keys.into_iter() {
        assert!(registry::contains_key(key),
                "Could not find key {}", key);
    }
}

#[test]
fn object_keys_equal() {
    wait_for_registry();

    let values = vec![
        ("bool", AccessFlags::all(), BOOL.to_json()),
        ("u64", AccessFlags::all(), U64.to_json()),
        ("i64", AccessFlags::all(), I64.to_json()),
        ("f64", AccessFlags::all(), F64.to_json()),
        ("text", AccessFlags::all(), TEXT.to_json()),
        ("point", AccessFlags::all(), POINT.to_json()),
        ("null", AccessFlags::all(), Json::Null),
        ("u64s", AccessFlags::all(), Json::Array(u64s())),

        ("readonly", AccessFlags::READ(), READONLY.to_json()),
        ("writeonly", AccessFlags::WRITE(), WRITEONLY.to_json()),
    ];

    for (name, flags, json) in values.into_iter() {
        let (found_flags, found) = registry::get_json(name)
            .expect(&format!("Unable to get key {}", name));
        assert_eq!(found_flags, flags);
        assert_eq!(*found, json);
    }
}

#[test]
fn key_perms() {
    wait_for_registry();

    let perms = vec![
        ("bool", AccessFlags::all()),
        ("readonly", AccessFlags::READ()),
        ("writeonly", AccessFlags::WRITE()),
        ("prop", AccessFlags::all()),
        //("prop_read", AccessFlags::READ()),
        //("prop_write", AccessFlags::WRITE())
    ];

    for (name, flags) in perms.into_iter() {
        let found_data = registry::get_data(name)
            .expect(&format!("Could not get data for {}", name));

        let (found_flags, _) = found_data.resolve();
        println!("Testing flags for {}", name);
        assert_eq!(found_flags, flags);
    }
}

<commit_msg>Fix warnings in tests<commit_after>//! Tests for the registry

use std::sync::{Arc, Mutex, Condvar};

use rustc_serialize::json::{Json, ToJson};

use registry;
use registry::AccessFlags;

lazy_static! {
    static ref ACCESS_PAIR: Arc<(Mutex<bool>, Condvar)>
        = Arc::new((Mutex::new(false), Condvar::new()));
}

// Constants for use with registry-accessing tests

pub const BOOL: bool = true;
pub const U64: u64 = 42;
pub const I64: i64 = -1;
pub const F64: f64 = 21.5;

pub const TEXT: &'static str = "Hello way-cooler";
pub const POINT: Point = Point { x: 12, y: 12 };

pub const READONLY: &'static str = "read only text";
pub const WRITEONLY: &'static str = "write only text";
pub const NO_PERMS: &'static str = "<look ma no perms>";

pub const PROP_GET_RESULT: &'static str = "get property";

pub fn get_prop() -> Json {
    PROP_GET_RESULT.to_json()
}

pub fn set_prop(json: Json) {
    println!("set_prop: got {:?}", json);
}

pub fn command() {
    println!("command executed!");
}

/// [0, 1, 2]
pub fn u64s() -> Vec<Json> {
    vec![Json::U64(0), Json::U64(1), Json::U64(2)]
}

/// Wait for the registry to initialize
pub fn wait_for_registry() {
    // First star for lazy static, second for Arc
    let &(ref lock, ref cond) = &**ACCESS_PAIR;
    let mut started = lock.lock().expect("Unable to lock ACCESS_PAIR lock!");
    while !*started {
        started = cond.wait(started)
            .expect("Oh boy, I can't wait for the registry to start!");
    }
}

json_convertible! {
    /// Has an x and y field
    #[derive(Debug, Clone, Eq, PartialEq)]
    struct Point {
        x: i32,
        y: i32
    }
}

unsafe impl Sync for Point {}

#[test]
fn add_keys() {
    let values = vec![
        ("bool", AccessFlags::all(), BOOL.to_json()),
        ("u64", AccessFlags::all(), U64.to_json()),
        ("i64", AccessFlags::all(), I64.to_json()),
        ("f64", AccessFlags::all(), F64.to_json()),
        ("text", AccessFlags::all(), TEXT.to_json()),
        ("point", AccessFlags::all(), POINT.to_json()),
        ("null", AccessFlags::all(), Json::Null),
        ("u64s", AccessFlags::all(), Json::Array(u64s())),

        ("readonly", AccessFlags::READ(), READONLY.to_json()),
        ("writeonly", AccessFlags::WRITE(), WRITEONLY.to_json()),
        ("noperms", AccessFlags::empty(), NO_PERMS.to_json())
    ];

    for (name, flags, json) in values.into_iter() {
        registry::set_json(name.to_string(), flags, json)
            .expect("Unable to initialize objects in registry");
    }

    registry::set_command("command".to_string(), Arc::new(command))
        .expect("Unable to initialize command in registry");

    registry::set_property_field("prop".to_string(),
                                 Some(Arc::new(get_prop)),
                                 Some(Arc::new(set_prop)))
        .expect("Unable to initialize property in registry");

    registry::set_property_field("prop_read".to_string(),
                                 Some(Arc::new(get_prop)),
                                 None)
        .expect("Unable to initialize property in registry");
    registry::set_property_field("prop_write".to_string(),
                                 None,
                                 Some(Arc::new(set_prop)))
        .expect("Unable to initialize property in registry");

    // Allow waiting threads to continue
    let &(ref lock, ref cond) = &**ACCESS_PAIR;
    let mut started = lock.lock().expect("Couldn't unlock threads");
    *started = true;
    cond.notify_all();
}

#[test]
fn contains_keys() {
    wait_for_registry();

    let keys = [
        "bool", "u64", "i64", "f64", "null", "text", "point",
        "u64s", "readonly", "writeonly", "prop", "noperms",
        "prop_read", "prop_write", "command",
    ];
    for key in keys.into_iter() {
        assert!(registry::contains_key(key),
                "Could not find key {}", key);
    }
}

#[test]
fn object_keys_equal() {
    wait_for_registry();

    let values = vec![
        ("bool", AccessFlags::all(), BOOL.to_json()),
        ("u64", AccessFlags::all(), U64.to_json()),
        ("i64", AccessFlags::all(), I64.to_json()),
        ("f64", AccessFlags::all(), F64.to_json()),
        ("text", AccessFlags::all(), TEXT.to_json()),
        ("point", AccessFlags::all(), POINT.to_json()),
        ("null", AccessFlags::all(), Json::Null),
        ("u64s", AccessFlags::all(), Json::Array(u64s())),

        ("readonly", AccessFlags::READ(), READONLY.to_json()),
        ("writeonly", AccessFlags::WRITE(), WRITEONLY.to_json()),
        ("noperms", AccessFlags::empty(), NO_PERMS.to_json())
    ];

    for (name, flags, json) in values.into_iter() {
        let (found_flags, found) = registry::get_json(name)
            .expect(&format!("Unable to get key {}", name));
        assert_eq!(found_flags, flags);
        assert_eq!(*found, json);
    }
}

#[test]
fn key_perms() {
    wait_for_registry();

    let perms = vec![
        ("bool", AccessFlags::all()),
        ("readonly", AccessFlags::READ()),
        ("writeonly", AccessFlags::WRITE()),
        ("prop", AccessFlags::all()),
        //("prop_read", AccessFlags::READ()),
        //("prop_write", AccessFlags::WRITE())
    ];

    for (name, flags) in perms.into_iter() {
        let found_data = registry::get_data(name)
            .expect(&format!("Could not get data for {}", name));

        let (found_flags, _) = found_data.resolve();
        println!("Testing flags for {}", name);
        assert_eq!(found_flags, flags);
    }
}

<|endoftext|>


<commit_before>use std::os::raw::c_void;

use gl;
use gltf;
use gltf::json::texture::MinFilter;

use image::DynamicImage::*;
use image::GenericImage;
use image::FilterType;

pub struct Texture {
    pub index: usize, // glTF index
    pub name: Option<String>,

    pub id: u32, // OpenGL id
}

// TODO!!: broken texture rendering: Suzanne (all black; base color factor makes it white)
impl Texture {
    pub fn from_gltf(g_texture: &gltf::texture::Texture) -> Texture {
        let mut texture_id = 0;
        unsafe {
            gl::GenTextures(1, &mut texture_id);
            gl::BindTexture(gl::TEXTURE_2D, texture_id);
        }
        let (needs_power_of_two, generate_mip_maps) =
            unsafe { Self::set_sampler_params(g_texture.sampler()) };

        // TODO!: share images via Rc? detect if occurs?
        let img = g_texture.source();
        let dyn_img = img.data();

        let format = match *dyn_img {
            ImageLuma8(_) => gl::RED,
            ImageLumaA8(_) => gl::RG,
            ImageRgb8(_) => gl::RGB,
            ImageRgba8(_) => gl::RGBA,
        };

        // **Non-Power-Of-Two Texture Implementation Note**: glTF does not guarantee that a texture's
        // dimensions are a power-of-two.  At runtime, if a texture's width or height is not a
        // power-of-two, the texture needs to be resized so its dimensions are powers-of-two if the
        // `sampler` the texture references
        // * Has a wrapping mode (either `wrapS` or `wrapT`) equal to `REPEAT` or `MIRRORED_REPEAT`, or
        // * Has a minification filter (`minFilter`) that uses mipmapping (`NEAREST_MIPMAP_NEAREST`, \\
        //   `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`, or `LINEAR_MIPMAP_LINEAR`).
        let (width, height) = dyn_img.dimensions();
        let (data, width, height) =
            if needs_power_of_two && (!width.is_power_of_two() || !height.is_power_of_two()) {
                let nwidth = width.next_power_of_two();
                let nheight = height.next_power_of_two();
                let resized = dyn_img.resize(nwidth, nheight, FilterType::Lanczos3);
                (resized.raw_pixels(), resized.width(), resized.height())
            }
            else {
                (dyn_img.raw_pixels(), dyn_img.width(), dyn_img.height())
            };

        unsafe {
            gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, width as i32, height as i32,
                0, format, gl::UNSIGNED_BYTE, &data[0] as *const u8 as *const c_void);

            if generate_mip_maps {
                gl::GenerateMipmap(gl::TEXTURE_2D);
            }
        }
        Texture {
            index: g_texture.index(),
            name: g_texture.name().map(|s| s.into()),
            id: texture_id,
        }
    }

    // Returns whether image needs to be Power-Of-Two-sized and whether mip maps should be generated
    // TODO: refactor return type into enum?
    unsafe fn set_sampler_params(sampler: gltf::texture::Sampler) -> (bool, bool) {
        // **Mipmapping Implementation Note**: When a sampler's minification filter (`minFilter`)
        // uses mipmapping (`NEAREST_MIPMAP_NEAREST`, `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`,
        // or `LINEAR_MIPMAP_LINEAR`), any texture referencing the sampler needs to have mipmaps,
        // e.g., by calling GL's `generateMipmap()` function.
        let mip_maps = match sampler.min_filter() {
            Some(MinFilter::NearestMipmapNearest) |
            Some(MinFilter::LinearMipmapNearest) |
            Some(MinFilter::NearestMipmapLinear) |
            Some(MinFilter::LinearMipmapLinear) |
            None => true, // see below
            _ => false
        };

        // **Default Filtering Implementation Note:** When filtering options are defined,
        // runtime must use them. Otherwise, it is free to adapt filtering to performance or quality goals.
        if let Some(min_filter) = sampler.min_filter() {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, min_filter.as_gl_enum());
        }
        else {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR as i32);
        }
        if let Some(mag_filter) = sampler.mag_filter() {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, mag_filter.as_gl_enum());
        }
        else {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        }

        let wrap_s = sampler.wrap_s().as_gl_enum();
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, wrap_s);
        let wrap_t = sampler.wrap_t().as_gl_enum();
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, wrap_t);

        let needs_power_of_two =
            wrap_s != gl::CLAMP_TO_EDGE as i32 ||
            wrap_t != gl::CLAMP_TO_EDGE as i32 ||
            mip_maps;
        (needs_power_of_two, mip_maps)
    }
}
<commit_msg>remove outdated comment<commit_after>use std::os::raw::c_void;

use gl;
use gltf;
use gltf::json::texture::MinFilter;

use image::DynamicImage::*;
use image::GenericImage;
use image::FilterType;

pub struct Texture {
    pub index: usize, // glTF index
    pub name: Option<String>,

    pub id: u32, // OpenGL id
}

impl Texture {
    pub fn from_gltf(g_texture: &gltf::texture::Texture) -> Texture {
        let mut texture_id = 0;
        unsafe {
            gl::GenTextures(1, &mut texture_id);
            gl::BindTexture(gl::TEXTURE_2D, texture_id);
        }
        let (needs_power_of_two, generate_mip_maps) =
            unsafe { Self::set_sampler_params(g_texture.sampler()) };

        // TODO!: share images via Rc? detect if occurs?
        let img = g_texture.source();
        let dyn_img = img.data();

        let format = match *dyn_img {
            ImageLuma8(_) => gl::RED,
            ImageLumaA8(_) => gl::RG,
            ImageRgb8(_) => gl::RGB,
            ImageRgba8(_) => gl::RGBA,
        };

        // **Non-Power-Of-Two Texture Implementation Note**: glTF does not guarantee that a texture's
        // dimensions are a power-of-two.  At runtime, if a texture's width or height is not a
        // power-of-two, the texture needs to be resized so its dimensions are powers-of-two if the
        // `sampler` the texture references
        // * Has a wrapping mode (either `wrapS` or `wrapT`) equal to `REPEAT` or `MIRRORED_REPEAT`, or
        // * Has a minification filter (`minFilter`) that uses mipmapping (`NEAREST_MIPMAP_NEAREST`, \\
        //   `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`, or `LINEAR_MIPMAP_LINEAR`).
        let (width, height) = dyn_img.dimensions();
        let (data, width, height) =
            if needs_power_of_two && (!width.is_power_of_two() || !height.is_power_of_two()) {
                let nwidth = width.next_power_of_two();
                let nheight = height.next_power_of_two();
                let resized = dyn_img.resize(nwidth, nheight, FilterType::Lanczos3);
                (resized.raw_pixels(), resized.width(), resized.height())
            }
            else {
                (dyn_img.raw_pixels(), dyn_img.width(), dyn_img.height())
            };

        unsafe {
            gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, width as i32, height as i32,
                0, format, gl::UNSIGNED_BYTE, &data[0] as *const u8 as *const c_void);

            if generate_mip_maps {
                gl::GenerateMipmap(gl::TEXTURE_2D);
            }
        }
        Texture {
            index: g_texture.index(),
            name: g_texture.name().map(|s| s.into()),
            id: texture_id,
        }
    }

    // Returns whether image needs to be Power-Of-Two-sized and whether mip maps should be generated
    // TODO: refactor return type into enum?
    unsafe fn set_sampler_params(sampler: gltf::texture::Sampler) -> (bool, bool) {
        // **Mipmapping Implementation Note**: When a sampler's minification filter (`minFilter`)
        // uses mipmapping (`NEAREST_MIPMAP_NEAREST`, `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`,
        // or `LINEAR_MIPMAP_LINEAR`), any texture referencing the sampler needs to have mipmaps,
        // e.g., by calling GL's `generateMipmap()` function.
        let mip_maps = match sampler.min_filter() {
            Some(MinFilter::NearestMipmapNearest) |
            Some(MinFilter::LinearMipmapNearest) |
            Some(MinFilter::NearestMipmapLinear) |
            Some(MinFilter::LinearMipmapLinear) |
            None => true, // see below
            _ => false
        };

        // **Default Filtering Implementation Note:** When filtering options are defined,
        // runtime must use them. Otherwise, it is free to adapt filtering to performance or quality goals.
        if let Some(min_filter) = sampler.min_filter() {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, min_filter.as_gl_enum());
        }
        else {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR as i32);
        }
        if let Some(mag_filter) = sampler.mag_filter() {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, mag_filter.as_gl_enum());
        }
        else {
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        }

        let wrap_s = sampler.wrap_s().as_gl_enum();
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, wrap_s);
        let wrap_t = sampler.wrap_t().as_gl_enum();
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, wrap_t);

        let needs_power_of_two =
            wrap_s != gl::CLAMP_TO_EDGE as i32 ||
            wrap_t != gl::CLAMP_TO_EDGE as i32 ||
            mip_maps;
        (needs_power_of_two, mip_maps)
    }
}
<|endoftext|>


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

//! Implementation of the `build` subcommand, used to compile a book.

use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::path::{Path, PathBuf};
use rustc_back::tempdir::TempDir;

use subcommand::Subcommand;
use term::Term;
use error::{err, CliResult, CommandResult};
use book;
use book::{Book, BookItem};
use css;
use javascript;

use rustdoc;

struct Build;

pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
    if name == "build" {
        Some(Box::new(Build))
    } else {
        None
    }
}

fn write_toc(book: &Book, path_to_root: &Path, out: &mut Write) -> io::Result<()> {
    fn walk_items(items: &[BookItem],
                  section: &str,
                  path_to_root: &Path,
                  out: &mut Write) -> io::Result<()> {
        for (i, item) in items.iter().enumerate() {
            try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], path_to_root, out));
        }
        Ok(())
    }
    fn walk_item(item: &BookItem,
                 section: &str,
                 path_to_root: &Path,
                 out: &mut Write) -> io::Result<()> {
        try!(writeln!(out, "
{} {}",
                 path_to_root.join(&item.path.with_extension("html")).display(),
                 section,
                 item.title));
        if !item.children.is_empty() {
            try!(writeln!(out, "
"));
            let _ = walk_items(&item.children[..], section, path_to_root, out);
            try!(writeln!(out, "
"));
        }
        try!(writeln!(out, "
"));

        Ok(())
    }

    try!(writeln!(out, "
"));
    try!(writeln!(out, "
"));
    try!(walk_items(&book.chapters[..], "", path_to_root, out));
    try!(writeln!(out, "
"));
    try!(writeln!(out, "
"));

    Ok(())
}

fn render(book: &Book, tgt: &Path) -> CliResult<()> {
    let tmp = try!(TempDir::new("rust-book"));

    for (_section, item) in book.iter() {
        let out_path = match item.path.parent() {
            Some(p) => tgt.join(p),
            None => tgt.to_path_buf(),
        };

        let src;
        if env::args().len() < 3 {
            src = env::current_dir().unwrap().clone();
        } else {
            src = PathBuf::from(&env::args().nth(2).unwrap());
        }
        // preprocess the markdown, rerouting markdown references to html
        // references
        let mut markdown_data = String::new();
        try!(File::open(&src.join(&item.path)).and_then(|mut f| {
            f.read_to_string(&mut markdown_data)
        }));
        let preprocessed_path = tmp.path().join(item.path.file_name().unwrap());
        {
            let urls = markdown_data.replace(".md)", ".html)");
            try!(File::create(&preprocessed_path).and_then(|mut f| {
                f.write_all(urls.as_bytes())
            }));
        }

        // write the prelude to a temporary HTML file for rustdoc inclusion
        let prelude = tmp.path().join("prelude.html");
        {
            let mut toc = BufWriter::new(try!(File::create(&prelude)));
            try!(writeln!(&mut toc, r#"

                <button id="toggle-nav">
                  Toggle navigation

                </button>

"#));
            let _ = write_toc(book, &item.path_to_root, &mut toc);
            try!(writeln!(&mut toc, "
"));
            try!(writeln!(&mut toc, "
"));
        }

        // write the postlude to a temporary HTML file for rustdoc inclusion
        let postlude = tmp.path().join("postlude.html");
        {
            let mut toc = BufWriter::new(try!(File::create(&postlude)));
            try!(toc.write_all(javascript::JAVASCRIPT.as_bytes()));
            try!(writeln!(&mut toc, "

"));
        }

        try!(fs::create_dir_all(&out_path));

        let rustdoc_args: &[String] = &[
            "".to_string(),
            preprocessed_path.display().to_string(),
            format!("-o{}", out_path.display()),
            format!("--html-before-content={}", prelude.display()),
            format!("--html-after-content={}", postlude.display()),
            format!("--markdown-playground-url=http://play.rust-lang.org"),
            format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()),
            "--markdown-no-toc".to_string(),
        ];
        let output_result = rustdoc::main_args(rustdoc_args);
        if output_result != 0 {
            let message = format!("Could not execute `rustdoc` with {:?}: {}",
                                  rustdoc_args, output_result);
            return Err(err(&message));
        }
    }

    // create index.html from the root README
    try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html")));

    // Copy some js for playpen
    let mut jquery = try!(File::create(tgt.join("jquery.js")));
    let js = include_bytes!("../librustdoc/html/static/jquery-2.1.0.min.js");
    try!(jquery.write_all(js));
    let mut playpen = try!(File::create(tgt.join("playpen.js")));
    let js = include_bytes!("../librustdoc/html/static/playpen.js");
    try!(playpen.write_all(js));
    Ok(())
}

impl Subcommand for Build {
    fn parse_args(&mut self, _: &[String]) -> CliResult<()> {
        Ok(())
    }
    fn usage(&self) {}
    fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
        let cwd = env::current_dir().unwrap();
        let src;
        let tgt;

        if env::args().len() < 3 {
            src = cwd.clone();
        } else {
            src = PathBuf::from(&env::args().nth(2).unwrap());
        }

        if env::args().len() < 4 {
            tgt = cwd.join("_book");
        } else {
            tgt = PathBuf::from(&env::args().nth(3).unwrap());
        }

        try!(fs::create_dir(&tgt));

        try!(File::create(&tgt.join("rust-book.css")).and_then(|mut f| {
            f.write_all(css::STYLE.as_bytes())
        }));

        let mut summary = try!(File::open(&src.join("SUMMARY.md")));
        match book::parse_summary(&mut summary, &src) {
            Ok(book) => {
                // execute rustdoc on the whole book
                render(&book, &tgt)
            }
            Err(errors) => {
                let n = errors.len();
                for err in errors {
                    term.err(&format!("error: {}", err)[..]);
                }

                Err(err(&format!("{} errors occurred", n)))
            }
        }
    }
}
<commit_msg>Delete `_book` folder if it exists from previous runs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of the `build` subcommand, used to compile a book.

use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::path::{Path, PathBuf};
use rustc_back::tempdir::TempDir;

use subcommand::Subcommand;
use term::Term;
use error::{err, CliResult, CommandResult};
use book;
use book::{Book, BookItem};
use css;
use javascript;

use rustdoc;

struct Build;

pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
    if name == "build" {
        Some(Box::new(Build))
    } else {
        None
    }
}

fn write_toc(book: &Book, path_to_root: &Path, out: &mut Write) -> io::Result<()> {
    fn walk_items(items: &[BookItem],
                  section: &str,
                  path_to_root: &Path,
                  out: &mut Write) -> io::Result<()> {
        for (i, item) in items.iter().enumerate() {
            try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], path_to_root, out));
        }
        Ok(())
    }
    fn walk_item(item: &BookItem,
                 section: &str,
                 path_to_root: &Path,
                 out: &mut Write) -> io::Result<()> {
        try!(writeln!(out, "
{} {}",
                 path_to_root.join(&item.path.with_extension("html")).display(),
                 section,
                 item.title));
        if !item.children.is_empty() {
            try!(writeln!(out, "
"));
            let _ = walk_items(&item.children[..], section, path_to_root, out);
            try!(writeln!(out, "
"));
        }
        try!(writeln!(out, "
"));

        Ok(())
    }

    try!(writeln!(out, "
"));
    try!(writeln!(out, "
"));
    try!(walk_items(&book.chapters[..], "", path_to_root, out));
    try!(writeln!(out, "
"));
    try!(writeln!(out, "
"));

    Ok(())
}

fn render(book: &Book, tgt: &Path) -> CliResult<()> {
    let tmp = try!(TempDir::new("rust-book"));

    for (_section, item) in book.iter() {
        let out_path = match item.path.parent() {
            Some(p) => tgt.join(p),
            None => tgt.to_path_buf(),
        };

        let src;
        if env::args().len() < 3 {
            src = env::current_dir().unwrap().clone();
        } else {
            src = PathBuf::from(&env::args().nth(2).unwrap());
        }
        // preprocess the markdown, rerouting markdown references to html
        // references
        let mut markdown_data = String::new();
        try!(File::open(&src.join(&item.path)).and_then(|mut f| {
            f.read_to_string(&mut markdown_data)
        }));
        let preprocessed_path = tmp.path().join(item.path.file_name().unwrap());
        {
            let urls = markdown_data.replace(".md)", ".html)");
            try!(File::create(&preprocessed_path).and_then(|mut f| {
                f.write_all(urls.as_bytes())
            }));
        }

        // write the prelude to a temporary HTML file for rustdoc inclusion
        let prelude = tmp.path().join("prelude.html");
        {
            let mut toc = BufWriter::new(try!(File::create(&prelude)));
            try!(writeln!(&mut toc, r#"

                <button id="toggle-nav">
                  Toggle navigation

                </button>

"#));
            let _ = write_toc(book, &item.path_to_root, &mut toc);
            try!(writeln!(&mut toc, "
"));
            try!(writeln!(&mut toc, "
"));
        }

        // write the postlude to a temporary HTML file for rustdoc inclusion
        let postlude = tmp.path().join("postlude.html");
        {
            let mut toc = BufWriter::new(try!(File::create(&postlude)));
            try!(toc.write_all(javascript::JAVASCRIPT.as_bytes()));
            try!(writeln!(&mut toc, "

"));
        }

        try!(fs::create_dir_all(&out_path));

        let rustdoc_args: &[String] = &[
            "".to_string(),
            preprocessed_path.display().to_string(),
            format!("-o{}", out_path.display()),
            format!("--html-before-content={}", prelude.display()),
            format!("--html-after-content={}", postlude.display()),
            format!("--markdown-playground-url=http://play.rust-lang.org"),
            format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()),
            "--markdown-no-toc".to_string(),
        ];
        let output_result = rustdoc::main_args(rustdoc_args);
        if output_result != 0 {
            let message = format!("Could not execute `rustdoc` with {:?}: {}",
                                  rustdoc_args, output_result);
            return Err(err(&message));
        }
    }

    // create index.html from the root README
    try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html")));

    // Copy some js for playpen
    let mut jquery = try!(File::create(tgt.join("jquery.js")));
    let js = include_bytes!("../librustdoc/html/static/jquery-2.1.0.min.js");
    try!(jquery.write_all(js));
    let mut playpen = try!(File::create(tgt.join("playpen.js")));
    let js = include_bytes!("../librustdoc/html/static/playpen.js");
    try!(playpen.write_all(js));
    Ok(())
}

impl Subcommand for Build {
    fn parse_args(&mut self, _: &[String]) -> CliResult<()> {
        Ok(())
    }
    fn usage(&self) {}
    fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
        let cwd = env::current_dir().unwrap();
        let src;
        let tgt;

        if env::args().len() < 3 {
            src = cwd.clone();
        } else {
            src = PathBuf::from(&env::args().nth(2).unwrap());
        }

        if env::args().len() < 4 {
            tgt = cwd.join("_book");
        } else {
            tgt = PathBuf::from(&env::args().nth(3).unwrap());
        }

        // `_book` directory may already exist from previous runs. Check and
        // delete it if it exists.
        for entry in try!(fs::read_dir(&cwd)) {
            let path = try!(entry).path();
            if path == tgt { try!(fs::remove_dir_all(&tgt)) }
        }
        try!(fs::create_dir(&tgt));

        try!(File::create(&tgt.join("rust-book.css")).and_then(|mut f| {
            f.write_all(css::STYLE.as_bytes())
        }));

        let mut summary = try!(File::open(&src.join("SUMMARY.md")));
        match book::parse_summary(&mut summary, &src) {
            Ok(book) => {
                // execute rustdoc on the whole book
                render(&book, &tgt)
            }
            Err(errors) => {
                let n = errors.len();
                for err in errors {
                    term.err(&format!("error: {}", err)[..]);
                }

                Err(err(&format!("{} errors occurred", n)))
            }
        }
    }
}
<|endoftext|>