<commit_before>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use super::control_prelude::*;
use std::borrow::Cow;

#[derive(Clone)]
pub struct Text(HandleRc);

impl Text {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            let ih = IupText(ptr::null_mut());
            Text(HandleRc::new(ih))
        }
    }

    pub fn value(&self) -> String {
        get_str_attribute(self.handle(), "VALUE\0")
    }
    pub unsafe fn value_slice(&self) -> Cow<str> {
        get_str_attribute_slice(self.handle(), "VALUE\0")
    }

    pub fn set_value(&self, value: &str) -> &Self {
        set_str_attribute(self.handle(), "VALUE\0", value);
        self
    }

    /// Inserts text at the end of the current text. Ignored if called before the control is mapped.
    /// If this control is multiline, [`append_newline`](./struct.Text.html#method.append_newline)
    /// is true, and the current text is not empty, then a `'\n'` character will be automatically
    /// inserted before the appended text.
    pub fn append(&self, text: &str) -> &Self {
        set_str_attribute(self.handle(), "APPEND\0", text);
        self
    }

    /// If true, this control is multiline, and the current text is not empty, then a `'\n'`
    /// character will be automatically inserted before text appended using `append`.
    ///
    /// The default is true.
    pub fn append_newline(&self) -> bool {
        unsafe {
            get_str_attribute_slice(self.handle(), "APPENDNEWLINE\0") == "YES"
        }
    }

    /// See [`append_newline`](./struct.Text.html#method.append_newline)
    pub fn set_append_newline(&self, enabled: bool) -> &Self {
        set_str_attribute(self.handle(), "APPENDNEWLINE\0", if enabled { "YES\0" } else { "NO\0" });
        self
    }

    pub fn multiline(&self) -> bool {
        unsafe {
            get_str_attribute_slice(self.handle(), "MULTILINE\0") == "YES"
        }
    }

    pub fn set_multiline(&self, multiline: bool) -> &Self {
        set_str_attribute(self.handle(), "MULTILINE\0", if multiline { "YES\0" } else { "NO\0" });
        self
    }

    pub fn visible_columns(&self) -> i32 {
        unsafe {
            let val = get_str_attribute_slice(self.handle(), "VISIBLECOLUMNS\0");
            val.parse().expect("could not convert VISIBLECOLUMNS to an integer")
        }
    }

    pub fn set_visible_columns(&self, columns: i32) -> &Self {
        set_str_attribute(self.handle(), "VISIBLECOLUMNS\0", &columns.to_string());
        self
    }

    pub fn visible_lines(&self) -> i32 {
        unsafe {
            let val = get_str_attribute_slice(self.handle(), "VISIBLELINES\0");
            val.parse().expect("could not convert VISIBLELINES to an integer")
        }
    }

    pub fn set_visible_lines(&self, lines: i32) -> &Self {
        set_str_attribute(self.handle(), "VISIBLELINES\0", &lines.to_string());
        self
    }
}

impl_control_traits!(Text);

impl ActiveAttribute for Text {}
impl CanFocusAttribute for Text {}
impl ExpandAttribute for Text {}
impl MinMaxSizeAttribute for Text {}
impl ScrollbarAttribute for Text {}
impl TipAttribute for Text {}
impl VisibleAttribute for Text {}
impl VisibleColumnsLinesAttribute for Text {}

impl MenuCommonCallbacks for Text {}
impl GetKillFocusCallbacks for Text {}
impl EnterLeaveWindowCallbacks for Text {}
impl ValueChangedCallback for Text {}

#[derive(Clone)]
pub struct CaretArgs {
    pub lin: usize,
    pub col: usize,
    pub pos: usize,
    _dummy: (),
}

impl_callbacks! {
    Text {
        "CARET_CB\0" => caret_event {
            CARET_CALLBACKS<FnMut(&CaretArgs), CaretCallbackToken>
        }
        unsafe extern fn caret_cb(ih: *mut Ihandle, lin: c_int, col: c_int, pos: c_int) -> c_int {
            with_callbacks(ih, &CARET_CALLBACKS, |cbs| {
                let args = CaretArgs {
                    lin: lin as usize,
                    col: col as usize,
                    pos: pos as usize,
                    _dummy: (),
                };
                for cb in cbs {
                    (&mut *cb.1.borrow_mut())(&args);
                }
                IUP_DEFAULT
            })
        }
    }
}
<commit_msg>Delete Text::visible_{columns,lines} because the trait provides them<commit_after>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use super::control_prelude::*;
use std::borrow::Cow;

#[derive(Clone)]
pub struct Text(HandleRc);

impl Text {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            let ih = IupText(ptr::null_mut());
            Text(HandleRc::new(ih))
        }
    }

    pub fn value(&self) -> String {
        get_str_attribute(self.handle(), "VALUE\0")
    }
    pub unsafe fn value_slice(&self) -> Cow<str> {
        get_str_attribute_slice(self.handle(), "VALUE\0")
    }

    pub fn set_value(&self, value: &str) -> &Self {
        set_str_attribute(self.handle(), "VALUE\0", value);
        self
    }

    /// Inserts text at the end of the current text. Ignored if called before the control is mapped.
    /// If this control is multiline, [`append_newline`](./struct.Text.html#method.append_newline)
    /// is true, and the current text is not empty, then a `'\n'` character will be automatically
    /// inserted before the appended text.
    pub fn append(&self, text: &str) -> &Self {
        set_str_attribute(self.handle(), "APPEND\0", text);
        self
    }

    /// If true, this control is multiline, and the current text is not empty, then a `'\n'`
    /// character will be automatically inserted before text appended using `append`.
    ///
    /// The default is true.
    pub fn append_newline(&self) -> bool {
        unsafe {
            get_str_attribute_slice(self.handle(), "APPENDNEWLINE\0") == "YES"
        }
    }

    /// See [`append_newline`](./struct.Text.html#method.append_newline)
    pub fn set_append_newline(&self, enabled: bool) -> &Self {
        set_str_attribute(self.handle(), "APPENDNEWLINE\0", if enabled { "YES\0" } else { "NO\0" });
        self
    }

    pub fn multiline(&self) -> bool {
        unsafe {
            get_str_attribute_slice(self.handle(), "MULTILINE\0") == "YES"
        }
    }

    pub fn set_multiline(&self, multiline: bool) -> &Self {
        set_str_attribute(self.handle(), "MULTILINE\0", if multiline { "YES\0" } else { "NO\0" });
        self
    }
}

impl_control_traits!(Text);

impl ActiveAttribute for Text {}
impl CanFocusAttribute for Text {}
impl ExpandAttribute for Text {}
impl MinMaxSizeAttribute for Text {}
impl ScrollbarAttribute for Text {}
impl TipAttribute for Text {}
impl VisibleAttribute for Text {}
impl VisibleColumnsLinesAttribute for Text {}

impl MenuCommonCallbacks for Text {}
impl GetKillFocusCallbacks for Text {}
impl EnterLeaveWindowCallbacks for Text {}
impl ValueChangedCallback for Text {}

#[derive(Clone)]
pub struct CaretArgs {
    pub lin: usize,
    pub col: usize,
    pub pos: usize,
    _dummy: (),
}

impl_callbacks! {
    Text {
        "CARET_CB\0" => caret_event {
            CARET_CALLBACKS<FnMut(&CaretArgs), CaretCallbackToken>
        }
        unsafe extern fn caret_cb(ih: *mut Ihandle, lin: c_int, col: c_int, pos: c_int) -> c_int {
            with_callbacks(ih, &CARET_CALLBACKS, |cbs| {
                let args = CaretArgs {
                    lin: lin as usize,
                    col: col as usize,
                    pos: pos as usize,
                    _dummy: (),
                };
                for cb in cbs {
                    (&mut *cb.1.borrow_mut())(&args);
                }
                IUP_DEFAULT
            })
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::ffi::CString;
use std::fs::File;
use std::io::{Error, ErrorKind, Result};
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::MetadataExt;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::raw::off_t;
use std::path::Path;

pub fn duplicate(file: &File) -> Result<File> {
    unsafe {
        let fd = libc::dup(file.as_raw_fd());

        if fd < 0 {
            Err(Error::last_os_error())
        } else {
            Ok(File::from_raw_fd(fd))
        }
    }
}

pub fn lock_shared(file: &File) -> Result<()> {
    flock(file, libc::LOCK_SH)
}

pub fn lock_exclusive(file: &File) -> Result<()> {
    flock(file, libc::LOCK_EX)
}

pub fn try_lock_shared(file: &File) -> Result<()> {
    flock(file, libc::LOCK_SH | libc::LOCK_NB)
}

pub fn try_lock_exclusive(file: &File) -> Result<()> {
    flock(file, libc::LOCK_EX | libc::LOCK_NB)
}

pub fn unlock(file: &File) -> Result<()> {
    flock(file, libc::LOCK_UN)
}

pub fn lock_error() -> Error {
    Error::from_raw_os_error(libc::EWOULDBLOCK)
}

fn flock(file: &File, flag: libc::c_int) -> Result<()> {
    let ret = unsafe { libc::flock(file.as_raw_fd(), flag) };
    if ret < 0 { Err(Error::last_os_error()) } else { Ok(()) }
}

pub fn allocated_size(file: &File) -> Result<u64> {
    file.metadata().map(|m| m.blocks() as u64 * 512)
}

#[cfg(any(target_os = "linux",
          target_os = "freebsd",
          target_os = "android",
          target_os = "nacl"))]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    let ret = unsafe { libc::posix_fallocate(file.as_raw_fd(), 0, len as off_t) };
    if ret == 0 { Ok(()) } else { Err(Error::last_os_error()) }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    let stat = try!(file.metadata());

    if len > stat.blocks() as u64 * 512 {
        let mut fstore = libc::fstore_t {
            fst_flags: libc::F_ALLOCATECONTIG,
            fst_posmode: libc::F_PEOFPOSMODE,
            fst_offset: 0,
            fst_length: len as off_t,
            fst_bytesalloc: 0,
        };

        let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) };
        if ret == -1 {
            // Unable to allocate contiguous disk space; attempt to allocate non-contiguously.
            fstore.fst_flags = libc::F_ALLOCATEALL;
            let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) };
            if ret == -1 {
                return Err(Error::last_os_error());
            }
        }
    }

    if len > stat.size() as u64 {
        file.set_len(len)
    } else {
        Ok(())
    }
}

#[cfg(any(target_os = "openbsd",
          target_os = "netbsd"))]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    // No file allocation API available, just set the length if necessary.
    if len > try!(file.metadata()).len() as u64 {
        file.set_len(len)
    } else {
        Ok(())
    }
}

fn statvfs<P>(path: P) -> Result<libc::statvfs> where P: AsRef<Path> {
    let cstr = match CString::new(path.as_ref().as_os_str().as_bytes()) {
        Ok(cstr) => cstr,
        Err(..) => return Err(Error::new(ErrorKind::InvalidInput, "path contained a null")),
    };

    unsafe {
        let mut stat: libc::statvfs = mem::zeroed();
        if libc::statvfs(cstr.as_ptr(), &mut stat) == -1 {
            Err(Error::last_os_error())
        } else {
            Ok(stat)
        }
    }
}

pub fn free_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64 * statvfs.f_bfree as u64)
}

pub fn available_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64 * statvfs.f_bavail as u64)
}

pub fn total_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64 * statvfs.f_blocks as u64)
}

pub fn allocation_granularity<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64)
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    extern crate libc;

    use std::fs::{self, File};
    use std::os::unix::io::AsRawFd;

    use {FileExt, lock_contended_error};

    /// The duplicate method returns a file with a new file descriptor.
    #[test]
    fn duplicate_new_fd() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();
        assert!(file1.as_raw_fd() != file2.as_raw_fd());
    }

    /// The duplicate method should preservesthe close on exec flag.
    #[test]
    fn duplicate_cloexec() {

        fn flags(file: &File) -> libc::c_int {
            unsafe { libc::fcntl(file.as_raw_fd(), libc::F_GETFL, 0) }
        }

        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();

        assert_eq!(flags(&file1), flags(&file2));
    }

    /// Tests that locking a file descriptor will replace any existing locks
    /// held on the file descriptor.
    #[test]
    fn lock_replace() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().create(true).open(&path).unwrap();
        let file2 = fs::OpenOptions::new().create(true).open(&path).unwrap();

        // Creating a shared lock will drop an exclusive lock.
        file1.lock_exclusive().unwrap();
        file1.lock_shared().unwrap();
        file2.lock_shared().unwrap();

        // Attempting to replace a shared lock with an exclusive lock will fail
        // with multiple lock holders, and remove the original shared lock.
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
        file1.lock_shared().unwrap();
    }

    /// Tests that locks are shared among duplicated file descriptors.
    #[test]
    fn lock_duplicate() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();
        let file3 = fs::OpenOptions::new().create(true).open(&path).unwrap();

        // Create a lock through fd1, then replace it through fd2.
        file1.lock_shared().unwrap();
        file2.lock_exclusive().unwrap();
        assert_eq!(file3.try_lock_shared().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Either of the file descriptors should be able to unlock.
        file1.unlock().unwrap();
        file3.lock_shared().unwrap();
    }
}
<commit_msg>Add cast for platforms where c_char is signed, fixes #1<commit_after>extern crate libc;

use std::ffi::CString;
use std::fs::File;
use std::io::{Error, ErrorKind, Result};
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::MetadataExt;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::raw::off_t;
use std::path::Path;

pub fn duplicate(file: &File) -> Result<File> {
    unsafe {
        let fd = libc::dup(file.as_raw_fd());

        if fd < 0 {
            Err(Error::last_os_error())
        } else {
            Ok(File::from_raw_fd(fd))
        }
    }
}

pub fn lock_shared(file: &File) -> Result<()> {
    flock(file, libc::LOCK_SH)
}

pub fn lock_exclusive(file: &File) -> Result<()> {
    flock(file, libc::LOCK_EX)
}

pub fn try_lock_shared(file: &File) -> Result<()> {
    flock(file, libc::LOCK_SH | libc::LOCK_NB)
}

pub fn try_lock_exclusive(file: &File) -> Result<()> {
    flock(file, libc::LOCK_EX | libc::LOCK_NB)
}

pub fn unlock(file: &File) -> Result<()> {
    flock(file, libc::LOCK_UN)
}

pub fn lock_error() -> Error {
    Error::from_raw_os_error(libc::EWOULDBLOCK)
}

fn flock(file: &File, flag: libc::c_int) -> Result<()> {
    let ret = unsafe { libc::flock(file.as_raw_fd(), flag) };
    if ret < 0 { Err(Error::last_os_error()) } else { Ok(()) }
}

pub fn allocated_size(file: &File) -> Result<u64> {
    file.metadata().map(|m| m.blocks() as u64 * 512)
}

#[cfg(any(target_os = "linux",
          target_os = "freebsd",
          target_os = "android",
          target_os = "nacl"))]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    let ret = unsafe { libc::posix_fallocate(file.as_raw_fd(), 0, len as off_t) };
    if ret == 0 { Ok(()) } else { Err(Error::last_os_error()) }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    let stat = try!(file.metadata());

    if len > stat.blocks() as u64 * 512 {
        let mut fstore = libc::fstore_t {
            fst_flags: libc::F_ALLOCATECONTIG,
            fst_posmode: libc::F_PEOFPOSMODE,
            fst_offset: 0,
            fst_length: len as off_t,
            fst_bytesalloc: 0,
        };

        let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) };
        if ret == -1 {
            // Unable to allocate contiguous disk space; attempt to allocate non-contiguously.
            fstore.fst_flags = libc::F_ALLOCATEALL;
            let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) };
            if ret == -1 {
                return Err(Error::last_os_error());
            }
        }
    }

    if len > stat.size() as u64 {
        file.set_len(len)
    } else {
        Ok(())
    }
}

#[cfg(any(target_os = "openbsd",
          target_os = "netbsd"))]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    // No file allocation API available, just set the length if necessary.
    if len > try!(file.metadata()).len() as u64 {
        file.set_len(len)
    } else {
        Ok(())
    }
}

fn statvfs<P>(path: P) -> Result<libc::statvfs> where P: AsRef<Path> {
    let cstr = match CString::new(path.as_ref().as_os_str().as_bytes()) {
        Ok(cstr) => cstr,
        Err(..) => return Err(Error::new(ErrorKind::InvalidInput, "path contained a null")),
    };

    unsafe {
        let mut stat: libc::statvfs = mem::zeroed();
        // danburkert/fs2-rs#1: cast is necessary for platforms where c_char != u8.
        if libc::statvfs(cstr.as_ptr() as *const _, &mut stat) == -1 {
            Err(Error::last_os_error())
        } else {
            Ok(stat)
        }
    }
}

pub fn free_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64 * statvfs.f_bfree as u64)
}

pub fn available_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64 * statvfs.f_bavail as u64)
}

pub fn total_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64 * statvfs.f_blocks as u64)
}

pub fn allocation_granularity<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    statvfs(path).map(|statvfs| statvfs.f_frsize as u64)
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    extern crate libc;

    use std::fs::{self, File};
    use std::os::unix::io::AsRawFd;

    use {FileExt, lock_contended_error};

    /// The duplicate method returns a file with a new file descriptor.
    #[test]
    fn duplicate_new_fd() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();
        assert!(file1.as_raw_fd() != file2.as_raw_fd());
    }

    /// The duplicate method should preservesthe close on exec flag.
    #[test]
    fn duplicate_cloexec() {

        fn flags(file: &File) -> libc::c_int {
            unsafe { libc::fcntl(file.as_raw_fd(), libc::F_GETFL, 0) }
        }

        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();

        assert_eq!(flags(&file1), flags(&file2));
    }

    /// Tests that locking a file descriptor will replace any existing locks
    /// held on the file descriptor.
    #[test]
    fn lock_replace() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().create(true).open(&path).unwrap();
        let file2 = fs::OpenOptions::new().create(true).open(&path).unwrap();

        // Creating a shared lock will drop an exclusive lock.
        file1.lock_exclusive().unwrap();
        file1.lock_shared().unwrap();
        file2.lock_shared().unwrap();

        // Attempting to replace a shared lock with an exclusive lock will fail
        // with multiple lock holders, and remove the original shared lock.
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
        file1.lock_shared().unwrap();
    }

    /// Tests that locks are shared among duplicated file descriptors.
    #[test]
    fn lock_duplicate() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();
        let file3 = fs::OpenOptions::new().create(true).open(&path).unwrap();

        // Create a lock through fd1, then replace it through fd2.
        file1.lock_shared().unwrap();
        file2.lock_exclusive().unwrap();
        assert_eq!(file3.try_lock_shared().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Either of the file descriptors should be able to unlock.
        file1.unlock().unwrap();
        file3.lock_shared().unwrap();
    }
}
<|endoftext|>


<commit_before>use embed::{ConvertVec4, PopVariable, PushVariable};
use {
    Runtime,
    Variable,
};

/// Wraps a 4D vector for easier embedding with Dyon.
#[derive(Debug, Copy, Clone)]
pub struct Vec4(pub [f32; 4]);

impl ConvertVec4 for Vec4 {
    fn from(val: [f32; 4]) -> Self { Vec4(val) }
    fn to(&self) -> [f32; 4] { self.0 }
}

impl PopVariable for Vec4 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Vec4(v) = var {
            Ok(Vec4(v))
        } else {
            Err(rt.expected(var, "vec4"))
        }
    }
}

impl PushVariable for Vec4 {
    fn push_var(&self) -> Variable { Variable::Vec4(self.0) }
}

impl From<[f32; 2]> for Vec4 {
    fn from(val: [f32; 2]) -> Vec4 {
        Vec4([val[0], val[1], 0.0, 0.0])
    }
}

impl From<[f32; 3]> for Vec4 {
    fn from(val: [f32; 3]) -> Vec4 {
        Vec4([val[0], val[1], val[2], 0.0])
    }
}

impl From<[f32; 4]> for Vec4 {
    fn from(val: [f32; 4]) -> Vec4 {
        Vec4([val[0], val[1], val[2], val[3]])
    }
}

impl From<[f64; 2]> for Vec4 {
    fn from(val: [f64; 2]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, 0.0, 0.0])
    }
}

impl From<[f64; 3]> for Vec4 {
    fn from(val: [f64; 3]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, val[2] as f32, 0.0])
    }
}

impl From<[f64; 4]> for Vec4 {
    fn from(val: [f64; 4]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, val[2] as f32, val[3] as f32])
    }
}

impl From<(f32, f32)> for Vec4 {
    fn from(val: (f32, f32)) -> Vec4 {
        Vec4([val.0, val.1, 0.0, 0.0])
    }
}

impl From<(f32, f32, f32)> for Vec4 {
    fn from(val: (f32, f32, f32)) -> Vec4 {
        Vec4([val.0, val.1, val.2, 0.0])
    }
}

impl From<(f32, f32, f32, f32)> for Vec4 {
    fn from(val: (f32, f32, f32, f32)) -> Vec4 {
        Vec4([val.0, val.1, val.2, val.3])
    }
}

impl From<(f64, f64)> for Vec4 {
    fn from(val: (f64, f64)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, 0.0, 0.0])
    }
}

impl From<(f64, f64, f64)> for Vec4 {
    fn from(val: (f64, f64, f64)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, val.2 as f32, 0.0])
    }
}

impl From<(f64, f64, f64, f64)> for Vec4 {
    fn from(val: (f64, f64, f64, f64)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, val.2 as f32, val.3 as f32])
    }
}

impl Into<[f32; 2]> for Vec4 {
    fn into(self) -> [f32; 2] {
        [self.0[0], self.0[1]]
    }
}

impl Into<[f32; 3]> for Vec4 {
    fn into(self) -> [f32; 3] {
        [self.0[0], self.0[1], self.0[2]]
    }
}

impl Into<[f32; 4]> for Vec4 {
    fn into(self) -> [f32; 4] {
        self.0
    }
}

impl Into<[f64; 2]> for Vec4 {
    fn into(self) -> [f64; 2] {
        [self.0[0] as f64, self.0[1] as f64]
    }
}

impl Into<[f64; 3]> for Vec4 {
    fn into(self) -> [f64; 3] {
        [self.0[0] as f64, self.0[1] as f64, self.0[2] as f64]
    }
}

impl Into<[f64; 4]> for Vec4 {
    fn into(self) -> [f64; 4] {
        [self.0[0] as f64, self.0[1] as f64, self.0[2] as f64, self.0[3] as f64]
    }
}

impl Into<(f32, f32)> for Vec4 {
    fn into(self) -> (f32, f32) {
        (self.0[0], self.0[1])
    }
}

impl Into<(f32, f32, f32)> for Vec4 {
    fn into(self) -> (f32, f32, f32) {
        (self.0[0], self.0[1], self.0[2])
    }
}

impl Into<(f32, f32, f32, f32)> for Vec4 {
    fn into(self) -> (f32, f32, f32, f32) {
        (self.0[0], self.0[1], self.0[2], self.0[3])
    }
}

impl Into<(f64, f64)> for Vec4 {
    fn into(self) -> (f64, f64) {
        (self.0[0] as f64, self.0[1] as f64)
    }
}

impl Into<(f64, f64, f64)> for Vec4 {
    fn into(self) -> (f64, f64, f64) {
        (self.0[0] as f64, self.0[1] as f64, self.0[2] as f64)
    }
}

impl Into<(f64, f64, f64, f64)> for Vec4 {
    fn into(self) -> (f64, f64, f64, f64) {
        (self.0[0] as f64, self.0[1] as f64, self.0[2] as f64, self.0[3] as f64)
    }
}
<commit_msg>Added more conversions for `Vec4`<commit_after>use embed::{ConvertVec4, PopVariable, PushVariable};
use {
    Runtime,
    Variable,
};

/// Wraps a 4D vector for easier embedding with Dyon.
#[derive(Debug, Copy, Clone)]
pub struct Vec4(pub [f32; 4]);

impl ConvertVec4 for Vec4 {
    fn from(val: [f32; 4]) -> Self { Vec4(val) }
    fn to(&self) -> [f32; 4] { self.0 }
}

impl PopVariable for Vec4 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Vec4(v) = var {
            Ok(Vec4(v))
        } else {
            Err(rt.expected(var, "vec4"))
        }
    }
}

impl PushVariable for Vec4 {
    fn push_var(&self) -> Variable { Variable::Vec4(self.0) }
}

impl From<[f32; 2]> for Vec4 {
    fn from(val: [f32; 2]) -> Vec4 {
        Vec4([val[0], val[1], 0.0, 0.0])
    }
}

impl From<[f32; 3]> for Vec4 {
    fn from(val: [f32; 3]) -> Vec4 {
        Vec4([val[0], val[1], val[2], 0.0])
    }
}

impl From<[f32; 4]> for Vec4 {
    fn from(val: [f32; 4]) -> Vec4 {
        Vec4([val[0], val[1], val[2], val[3]])
    }
}

impl From<[f64; 2]> for Vec4 {
    fn from(val: [f64; 2]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, 0.0, 0.0])
    }
}

impl From<[f64; 3]> for Vec4 {
    fn from(val: [f64; 3]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, val[2] as f32, 0.0])
    }
}

impl From<[f64; 4]> for Vec4 {
    fn from(val: [f64; 4]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, val[2] as f32, val[3] as f32])
    }
}

impl From<(f32, f32)> for Vec4 {
    fn from(val: (f32, f32)) -> Vec4 {
        Vec4([val.0, val.1, 0.0, 0.0])
    }
}

impl From<(f32, f32, f32)> for Vec4 {
    fn from(val: (f32, f32, f32)) -> Vec4 {
        Vec4([val.0, val.1, val.2, 0.0])
    }
}

impl From<(f32, f32, f32, f32)> for Vec4 {
    fn from(val: (f32, f32, f32, f32)) -> Vec4 {
        Vec4([val.0, val.1, val.2, val.3])
    }
}

impl From<(f64, f64)> for Vec4 {
    fn from(val: (f64, f64)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, 0.0, 0.0])
    }
}

impl From<(f64, f64, f64)> for Vec4 {
    fn from(val: (f64, f64, f64)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, val.2 as f32, 0.0])
    }
}

impl From<(f64, f64, f64, f64)> for Vec4 {
    fn from(val: (f64, f64, f64, f64)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, val.2 as f32, val.3 as f32])
    }
}

impl From<[u32; 2]> for Vec4 {
    fn from(val: [u32; 2]) -> Vec4 {
        Vec4([val[0] as f32, val[1] as f32, 0.0, 0.0])
    }
}

impl From<(u32, u32)> for Vec4 {
    fn from(val: (u32, u32)) -> Vec4 {
        Vec4([val.0 as f32, val.1 as f32, 0.0, 0.0])
    }
}

impl From<[u8; 4]> for Vec4 {
    fn from(val: [u8; 4]) -> Vec4 {
        Vec4([val[0] as f32 / 255.0, val[1] as f32 / 255.0,
              val[2] as f32 / 255.0, val[3] as f32 / 255.0])
    }
}

impl From<(u8, u8, u8, u8)> for Vec4 {
    fn from(val: (u8, u8, u8, u8)) -> Vec4 {
        Vec4([val.0 as f32 / 255.0, val.1 as f32 / 255.0,
              val.2 as f32 / 255.0, val.3 as f32 / 255.0])
    }
}

impl Into<[f32; 2]> for Vec4 {
    fn into(self) -> [f32; 2] {
        [self.0[0], self.0[1]]
    }
}

impl Into<[f32; 3]> for Vec4 {
    fn into(self) -> [f32; 3] {
        [self.0[0], self.0[1], self.0[2]]
    }
}

impl Into<[f32; 4]> for Vec4 {
    fn into(self) -> [f32; 4] {
        self.0
    }
}

impl Into<[f64; 2]> for Vec4 {
    fn into(self) -> [f64; 2] {
        [self.0[0] as f64, self.0[1] as f64]
    }
}

impl Into<[f64; 3]> for Vec4 {
    fn into(self) -> [f64; 3] {
        [self.0[0] as f64, self.0[1] as f64, self.0[2] as f64]
    }
}

impl Into<[f64; 4]> for Vec4 {
    fn into(self) -> [f64; 4] {
        [self.0[0] as f64, self.0[1] as f64, self.0[2] as f64, self.0[3] as f64]
    }
}

impl Into<(f32, f32)> for Vec4 {
    fn into(self) -> (f32, f32) {
        (self.0[0], self.0[1])
    }
}

impl Into<(f32, f32, f32)> for Vec4 {
    fn into(self) -> (f32, f32, f32) {
        (self.0[0], self.0[1], self.0[2])
    }
}

impl Into<(f32, f32, f32, f32)> for Vec4 {
    fn into(self) -> (f32, f32, f32, f32) {
        (self.0[0], self.0[1], self.0[2], self.0[3])
    }
}

impl Into<(f64, f64)> for Vec4 {
    fn into(self) -> (f64, f64) {
        (self.0[0] as f64, self.0[1] as f64)
    }
}

impl Into<(f64, f64, f64)> for Vec4 {
    fn into(self) -> (f64, f64, f64) {
        (self.0[0] as f64, self.0[1] as f64, self.0[2] as f64)
    }
}

impl Into<(f64, f64, f64, f64)> for Vec4 {
    fn into(self) -> (f64, f64, f64, f64) {
        (self.0[0] as f64, self.0[1] as f64, self.0[2] as f64, self.0[3] as f64)
    }
}

impl Into<[u32; 2]> for Vec4 {
    fn into(self) -> [u32; 2] {
        [self.0[0] as u32, self.0[1] as u32]
    }
}

impl Into<(u32, u32)> for Vec4 {
    fn into(self) -> (u32, u32) {
        (self.0[0] as u32, self.0[1] as u32)
    }
}

impl Into<(u8, u8, u8, u8)> for Vec4 {
    fn into(self) -> (u8, u8, u8, u8) {
        ((self.0[0] * 255.0) as u8, (self.0[1] * 255.0) as u8,
         (self.0[2] * 255.0) as u8, (self.0[3] * 255.0) as u8)
    }
}

impl Into<[u8; 4]> for Vec4 {
    fn into(self) -> [u8; 4] {
        [(self.0[0] * 255.0) as u8, (self.0[1] * 255.0) as u8,
         (self.0[2] * 255.0) as u8, (self.0[3] * 255.0) as u8]
    }
}
<|endoftext|>


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

/// Null enumerations to define unit types
#[derive(Debug, Clone, Copy)]
struct Inch;
#[derive(Debug, Clone, Copy)]
struct Mm;

/// `Length` is phantom type with hidden parameter `Unit`
///
/// `f64` already implements the `Clone` and `Copy` traits
#[derive(Debug, Clone, Copy)]
struct Length<Unit>(f64,PhantomData<Unit>);

/// The `Add` trait defines the behavior of the `+` operator.
impl<Unit> Add for Length<Unit> {
     type Output = Length<Unit>;

    // add() returns a new `Length` struct containing the sum.
    fn add(self, rhs: Length<Unit>) -> Length<Unit> {
        // `+` calls the `Add` implementation for `f64`
        Length(self.0 + rhs.0, PhantomData)
    }
}

fn main() {
    // Specialize `one_foot` to have hidden parameter `Inch`
    let one_foot:  Length<Inch> = Length(12.0, PhantomData);
    // `one_meter` has hidden parameter `Mm`
    let one_meter: Length<Mm>   = Length(1000.0, PhantomData);

    // `+` calls the `add()` method we implemented for `Length<Unit>`
    //
    // Since `Length` implements `Clone` + `Copy`, `add()` does not consume
    // `one_foot` and `one_meter` but makes a copy of them in `self` and `rhs`
    let two_feet = one_foot + one_foot;
    let two_meters = one_meter + one_meter;

    // Addition works
    println!("one foot + one_foot = {:?}", two_feet);
    println!("one meter + one_meter = {:?}", two_meters);

    // Nonsensical operations fail as they should
    // Error: type mismatch
    //let one_feter = one_foot + one_meter;
}

<commit_msg>generics/phantom/testcase_units: mostly punctiation<commit_after>use std::ops::Add;
use std::marker::PhantomData;

/// Null enumerations define unit types.
#[derive(Debug, Clone, Copy)]
struct Inch;
#[derive(Debug, Clone, Copy)]
struct Mm;

/// `Length` is phantom type with hidden parameter `Unit`.
///
/// `f64` already implements the `Clone` and `Copy` traits.
#[derive(Debug, Clone, Copy)]
struct Length<Unit>(f64,PhantomData<Unit>);

/// The `Add` trait defines the behavior of the `+` operator.
impl<Unit> Add for Length<Unit> {
     type Output = Length<Unit>;

    // add() returns a new `Length` struct containing the sum.
    fn add(self, rhs: Length<Unit>) -> Length<Unit> {
        // `+` calls the `Add` implementation for `f64`.
        Length(self.0 + rhs.0, PhantomData)
    }
}

fn main() {
    // Specializes `one_foot` to have hidden parameter `Inch`.
    let one_foot:  Length<Inch> = Length(12.0, PhantomData);
    // `one_meter` has hidden parameter `Mm`.
    let one_meter: Length<Mm>   = Length(1000.0, PhantomData);

    // `+` calls the `add()` method we implemented for `Length<Unit>`.
    //
    // Since `Length` implements `Clone` + `Copy`, `add()` does not consume
    // `one_foot` and `one_meter` but makes a copy of them in `self` and `rhs`.
    let two_feet = one_foot + one_foot;
    let two_meters = one_meter + one_meter;

    // Addition works.
    println!("one foot + one_foot = {:?}", two_feet);
    println!("one meter + one_meter = {:?}", two_meters);

    // Nonsensical operations fail as they should:
    // Error: type mismatch.
    //let one_feter = one_foot + one_meter;
}

<|endoftext|>


<commit_before>use agent::Agent;
use random::Random;

#[test]
fn age() {
  let mut agent = Agent::new(10, Box::new(FakeRandom::new()));
  assert_eq!(0, agent.age());
  agent.update(3, 4.0);
  assert_eq!(1, agent.age());
}

struct FakeRandom {
  value: i16,
}

impl FakeRandom {
  fn new() -> FakeRandom {
    return FakeRandom {
      value: 4,
    };
  }
}

impl Random for FakeRandom {
  fn next_modulo(&mut self, limit: i64) -> i64 {
    return self.value as i64;
  }
}
<commit_msg>Fix broken test.<commit_after>use agent::Agent;
use random::Random;
use types::Reward;

#[test]
fn age() {
  let mut agent = Agent::new(10, Box::new(FakeRandom::new()));
  assert_eq!(0, agent.age());
  agent.update(3, Reward(4.0));
  assert_eq!(1, agent.age());
}

struct FakeRandom {
  value: i16,
}

impl FakeRandom {
  fn new() -> FakeRandom {
    return FakeRandom {
      value: 4,
    };
  }
}

impl Random for FakeRandom {
  fn next_modulo(&mut self, limit: i64) -> i64 {
    return self.value as i64;
  }
}
<|endoftext|>


<commit_before>use cargo::util::CargoResult;
use cargo::CargoError;
use context::CrateContext;
use context::WorkspaceContext;
use planning::PlannedBuild;
use rendering::BuildRenderer;
use rendering::FileOutputs;
use rendering::RenderDetails;
use tera::Context;
use tera::Tera;
use tera;

pub struct BazelRenderer {
  internal_renderer: Tera,
}

impl BazelRenderer {
  pub fn new() -> BazelRenderer {
    // Configure tera with a bogus template dir: We don't want any runtime template support
    let mut renderer = Tera::new("src/not/a/dir/*").unwrap();
    renderer.add_raw_templates(vec![
      ("templates/partials/rust_binary.template", include_str!("templates/partials/rust_binary.template")),
      ("templates/partials/rust_library.template", include_str!("templates/partials/rust_library.template")),
      ("templates/workspace.BUILD.template", include_str!("templates/workspace.BUILD.template")),
      ("templates/crate.BUILD.template", include_str!("templates/crate.BUILD.template"))]).unwrap();

    BazelRenderer {
      internal_renderer: renderer,
    }
  }

  pub fn render_crate(&self, workspace_context: &WorkspaceContext, package: &CrateContext) -> Result<String, tera::Error> {
    let mut context = Context::new();
    context.add("path_prefix", &workspace_context.workspace_prefix);
    context.add("crate", &package);
    self.internal_renderer.render("templates/crate.BUILD.template", &context)
  }

  pub fn render_aliases(&self, workspace_context: &WorkspaceContext, all_packages: &Vec<CrateContext>) -> Result<String, tera::Error> {
    let mut context = Context::new();
    context.add("path_prefix", &workspace_context.workspace_prefix);
    context.add("crates", &all_packages);
    self.internal_renderer.render("templates/workspace.BUILD.template", &context)
  }
}

impl BuildRenderer for BazelRenderer {
  fn render_planned_build(&mut self, render_details: &RenderDetails, planned_build: &PlannedBuild) -> CargoResult<Vec<FileOutputs>> {
    let &RenderDetails { ref path_prefix, .. } = render_details;
    let &PlannedBuild { ref workspace_context, ref crate_contexts, .. } = planned_build;
    let mut file_outputs = Vec::new();

    for package in crate_contexts {
      let build_file_path = format!("{}/{}BUILD", &path_prefix, &package.path);
      let rendered_crate_build_file = try!(self.render_crate(&workspace_context, &package).map_err(|e| CargoError::from(e.to_string())));
      file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_crate_build_file })
    }

    let build_file_path = format!("{}/vendor/BUILD", &path_prefix);
    let rendered_alias_build_file = try!(self.render_aliases(&workspace_context, &crate_contexts).map_err(|e| CargoError::from(e.to_string())));
    file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_alias_build_file });
    Ok(file_outputs)
  }
}

#[cfg(test)]
mod tests {
  pub use super::*;
  pub use planning::PlannedBuild;
  pub use rendering::RenderDetails;
  pub use rendering::FileOutputs;
  pub use context::*;
  pub use hamcrest::prelude::*;
  pub use hamcrest::core::expect;

  fn dummy_render_details() -> RenderDetails {
    RenderDetails {
      path_prefix: "./some_render_prefix".to_owned(),
    }
  }

  fn dummy_planned_build(crate_contexts: Vec<CrateContext>) -> PlannedBuild {
    PlannedBuild {
      workspace_context: WorkspaceContext {
        workspace_prefix: "//workspace/prefix".to_owned(),
        platform_triple: "irrelevant".to_owned(),
      },
      crate_contexts: crate_contexts,
    }
  }

  fn dummy_binary_crate() -> CrateContext {
    CrateContext {
      pkg_name: "test-binary".to_owned(),
      pkg_version: "1.1.1".to_owned(),
      features: vec!["feature1".to_owned(), "feature2".to_owned()].to_owned(),
      path: "vendor/test-binary-1.1.1/".to_owned(),
      dependencies: Vec::new(),
      build_dependencies: Vec::new(),
      dev_dependencies: Vec::new(),
      is_root_dependency: true,
      metadeps: Vec::new(),
      platform_triple: "irrelevant".to_owned(),
      targets: vec![
        BuildTarget {
          name: "some_binary".to_owned(),
          kind: "bin".to_owned(),
          path: "bin/main.rs".to_owned()
        }
      ],
      build_script_target: None,
    }
  }

  fn dummy_library_crate() -> CrateContext {
    CrateContext {
      pkg_name: "test-library".to_owned(),
      pkg_version: "1.1.1".to_owned(),
      features: vec!["feature1".to_owned(), "feature2".to_owned()].to_owned(),
      path: "vendor/test-library-1.1.1/".to_owned(),
      dependencies: Vec::new(),
      build_dependencies: Vec::new(),
      dev_dependencies: Vec::new(),
      is_root_dependency: true,
      metadeps: Vec::new(),
      platform_triple: "irrelevant".to_owned(),
      targets: vec![
        BuildTarget {
          name: "some_library".to_owned(),
          kind: "lib".to_owned(),
          path: "path/lib.rs".to_owned()
        }
      ],
      build_script_target: None,
    }
  }

  fn extract_contents_matching_path(file_outputs: &Vec<FileOutputs>, crate_name: &str) -> String {
    let mut matching_files_contents = file_outputs
      .iter()
      .filter(|output| output.path.contains(crate_name))
      .map(|output| output.contents.to_owned())
      .collect::<Vec<String>>();

    assert_that!(matching_files_contents.len(), equal_to(1));
    matching_files_contents.pop().unwrap()
  }

  fn render_crates_for_test(contexts: Vec<CrateContext>) -> Vec<FileOutputs> {
    BazelRenderer::new().render_planned_build(
      &dummy_render_details(),
      &dummy_planned_build(contexts)) .unwrap()
  }

  #[test]
  fn all_plans_contain_root_build_file() {
    let file_outputs = render_crates_for_test(Vec::new());
    let file_names = file_outputs.iter().map(|output| output.path.as_ref()).collect::<Vec<&str>>();

    assert_that!(&file_names, contains(vec!["./some_render_prefix/vendor/BUILD"]).exactly());
  }

  #[test]
  fn crates_generate_build_files() {
    let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
    let file_names = file_outputs.iter().map(|output| output.path.as_ref()).collect::<Vec<&str>>();

    assert_that!(&file_names,
                 contains(vec!["./some_render_prefix/vendor/BUILD", "./some_render_prefix/vendor/test-library-1.1.1/BUILD"]).exactly());
  }

  #[test]
  fn root_crates_get_build_aliases() {
    let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
    let root_build_contents = extract_contents_matching_path(&file_outputs, "vendor/BUILD");

    expect(root_build_contents.contains("alias"),
      format!("expected root build contents to contain an alias \
              for test-library crate, but it just contained [{}]", root_build_contents)).unwrap();
  }

  #[test]
  fn non_root_crates_dont_get_build_aliases() {
    let mut non_root_crate = dummy_library_crate();
    non_root_crate.is_root_dependency = false;

    let file_outputs = render_crates_for_test(vec![non_root_crate]);
    let root_build_contents = extract_contents_matching_path(&file_outputs, "vendor/BUILD");

    expect(!root_build_contents.contains("alias"),
      format!("expected root build contents not to contain an alias \
              for test-library crate, but it just contained [{}]", root_build_contents)).unwrap();
  }

  #[test]
  fn binaries_get_rust_binary_rules() {
    let file_outputs = render_crates_for_test(vec![dummy_binary_crate()]);
    let crate_build_contents = extract_contents_matching_path(&file_outputs, "vendor/test-binary-1.1.1/BUILD");

    expect(crate_build_contents.contains("rust_binary("),
      format!("expected crate build contents to contain rust_binary, \
              but it just contained [{}]", crate_build_contents)).unwrap();
  }

  #[test]
  fn libraries_get_rust_library_rules() {
    let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
    let crate_build_contents = extract_contents_matching_path(&file_outputs, "vendor/test-library-1.1.1/BUILD");

    expect(crate_build_contents.contains("rust_library("),
      format!("expected crate build contents to contain rust_library, \
              but it just contained [{}]", crate_build_contents)).unwrap();
  }
}
<commit_msg>Fix the tests<commit_after>use cargo::util::CargoResult;
use cargo::CargoError;
use context::CrateContext;
use context::WorkspaceContext;
use planning::PlannedBuild;
use rendering::BuildRenderer;
use rendering::FileOutputs;
use rendering::RenderDetails;
use tera::Context;
use tera::Tera;
use tera;

pub struct BazelRenderer {
  internal_renderer: Tera,
}

impl BazelRenderer {
  pub fn new() -> BazelRenderer {
    // Configure tera with a bogus template dir: We don't want any runtime template support
    let mut renderer = Tera::new("src/not/a/dir/*").unwrap();
    renderer.add_raw_templates(vec![
      ("templates/partials/rust_binary.template", include_str!("templates/partials/rust_binary.template")),
      ("templates/partials/rust_library.template", include_str!("templates/partials/rust_library.template")),
      ("templates/workspace.BUILD.template", include_str!("templates/workspace.BUILD.template")),
      ("templates/crate.BUILD.template", include_str!("templates/crate.BUILD.template"))]).unwrap();

    BazelRenderer {
      internal_renderer: renderer,
    }
  }

  pub fn render_crate(&self, workspace_context: &WorkspaceContext, package: &CrateContext) -> Result<String, tera::Error> {
    let mut context = Context::new();
    context.add("path_prefix", &workspace_context.workspace_prefix);
    context.add("crate", &package);
    self.internal_renderer.render("templates/crate.BUILD.template", &context)
  }

  pub fn render_aliases(&self, workspace_context: &WorkspaceContext, all_packages: &Vec<CrateContext>) -> Result<String, tera::Error> {
    let mut context = Context::new();
    context.add("path_prefix", &workspace_context.workspace_prefix);
    context.add("crates", &all_packages);
    self.internal_renderer.render("templates/workspace.BUILD.template", &context)
  }
}

impl BuildRenderer for BazelRenderer {
  fn render_planned_build(&mut self, render_details: &RenderDetails, planned_build: &PlannedBuild) -> CargoResult<Vec<FileOutputs>> {
    let &RenderDetails { ref path_prefix, .. } = render_details;
    let &PlannedBuild { ref workspace_context, ref crate_contexts, .. } = planned_build;
    let mut file_outputs = Vec::new();

    for package in crate_contexts {
      let build_file_path = format!("{}/{}BUILD", &path_prefix, &package.path);
      let rendered_crate_build_file = try!(self.render_crate(&workspace_context, &package).map_err(|e| CargoError::from(e.to_string())));
      file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_crate_build_file })
    }

    let build_file_path = format!("{}/vendor/BUILD", &path_prefix);
    let rendered_alias_build_file = try!(self.render_aliases(&workspace_context, &crate_contexts).map_err(|e| CargoError::from(e.to_string())));
    file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_alias_build_file });
    Ok(file_outputs)
  }
}

#[cfg(test)]
mod tests {
  pub use super::*;
  pub use planning::PlannedBuild;
  pub use rendering::RenderDetails;
  pub use rendering::FileOutputs;
  pub use context::*;
  pub use hamcrest::prelude::*;
  pub use hamcrest::core::expect;

  fn dummy_render_details() -> RenderDetails {
    RenderDetails {
      path_prefix: "./some_render_prefix".to_owned(),
    }
  }

  fn dummy_planned_build(crate_contexts: Vec<CrateContext>) -> PlannedBuild {
    PlannedBuild {
      workspace_context: WorkspaceContext {
        workspace_prefix: "//workspace/prefix".to_owned(),
        platform_triple: "irrelevant".to_owned(),
      },
      crate_contexts: crate_contexts,
    }
  }

  fn dummy_binary_crate() -> CrateContext {
    CrateContext {
      pkg_name: "test-binary".to_owned(),
      pkg_version: "1.1.1".to_owned(),
      features: vec!["feature1".to_owned(), "feature2".to_owned()].to_owned(),
      path: "vendor/test-binary-1.1.1/".to_owned(),
      dependencies: Vec::new(),
      build_dependencies: Vec::new(),
      dev_dependencies: Vec::new(),
      is_root_dependency: true,
      metadeps: Vec::new(),
      platform_triple: "irrelevant".to_owned(),
      targets: vec![
        BuildTarget {
          name: "some_binary".to_owned(),
          kind: "bin".to_owned(),
          path: "bin/main.rs".to_owned()
        }
      ],
      build_script_target: None,
      additional_deps: Vec::new(),
      additional_flags: Vec::new(),
    }
  }

  fn dummy_library_crate() -> CrateContext {
    CrateContext {
      pkg_name: "test-library".to_owned(),
      pkg_version: "1.1.1".to_owned(),
      features: vec!["feature1".to_owned(), "feature2".to_owned()].to_owned(),
      path: "vendor/test-library-1.1.1/".to_owned(),
      dependencies: Vec::new(),
      build_dependencies: Vec::new(),
      dev_dependencies: Vec::new(),
      is_root_dependency: true,
      metadeps: Vec::new(),
      platform_triple: "irrelevant".to_owned(),
      targets: vec![
        BuildTarget {
          name: "some_library".to_owned(),
          kind: "lib".to_owned(),
          path: "path/lib.rs".to_owned()
        }
      ],
      build_script_target: None,
      additional_deps: Vec::new(),
      additional_flags: Vec::new(),
    }
  }

  fn extract_contents_matching_path(file_outputs: &Vec<FileOutputs>, crate_name: &str) -> String {
    let mut matching_files_contents = file_outputs
      .iter()
      .filter(|output| output.path.contains(crate_name))
      .map(|output| output.contents.to_owned())
      .collect::<Vec<String>>();

    assert_that!(matching_files_contents.len(), equal_to(1));
    matching_files_contents.pop().unwrap()
  }

  fn render_crates_for_test(contexts: Vec<CrateContext>) -> Vec<FileOutputs> {
    BazelRenderer::new().render_planned_build(
      &dummy_render_details(),
      &dummy_planned_build(contexts)) .unwrap()
  }

  #[test]
  fn all_plans_contain_root_build_file() {
    let file_outputs = render_crates_for_test(Vec::new());
    let file_names = file_outputs.iter().map(|output| output.path.as_ref()).collect::<Vec<&str>>();

    assert_that!(&file_names, contains(vec!["./some_render_prefix/vendor/BUILD"]).exactly());
  }

  #[test]
  fn crates_generate_build_files() {
    let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
    let file_names = file_outputs.iter().map(|output| output.path.as_ref()).collect::<Vec<&str>>();

    assert_that!(&file_names,
                 contains(vec!["./some_render_prefix/vendor/BUILD", "./some_render_prefix/vendor/test-library-1.1.1/BUILD"]).exactly());
  }

  #[test]
  fn root_crates_get_build_aliases() {
    let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
    let root_build_contents = extract_contents_matching_path(&file_outputs, "vendor/BUILD");

    expect(root_build_contents.contains("alias"),
      format!("expected root build contents to contain an alias \
              for test-library crate, but it just contained [{}]", root_build_contents)).unwrap();
  }

  #[test]
  fn non_root_crates_dont_get_build_aliases() {
    let mut non_root_crate = dummy_library_crate();
    non_root_crate.is_root_dependency = false;

    let file_outputs = render_crates_for_test(vec![non_root_crate]);
    let root_build_contents = extract_contents_matching_path(&file_outputs, "vendor/BUILD");

    expect(!root_build_contents.contains("alias"),
      format!("expected root build contents not to contain an alias \
              for test-library crate, but it just contained [{}]", root_build_contents)).unwrap();
  }

  #[test]
  fn binaries_get_rust_binary_rules() {
    let file_outputs = render_crates_for_test(vec![dummy_binary_crate()]);
    let crate_build_contents = extract_contents_matching_path(&file_outputs, "vendor/test-binary-1.1.1/BUILD");

    expect(crate_build_contents.contains("rust_binary("),
      format!("expected crate build contents to contain rust_binary, \
              but it just contained [{}]", crate_build_contents)).unwrap();
  }

  #[test]
  fn libraries_get_rust_library_rules() {
    let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
    let crate_build_contents = extract_contents_matching_path(&file_outputs, "vendor/test-library-1.1.1/BUILD");

    expect(crate_build_contents.contains("rust_library("),
      format!("expected crate build contents to contain rust_library, \
              but it just contained [{}]", crate_build_contents)).unwrap();
  }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(core)]
#![feature(rand)]
#![feature(std_misc)]

extern crate murmurhash3;
extern crate test;

use std::time::duration::Duration;
use std::rand;
use std::rand::Rng;

use test::black_box;

use murmurhash3::murmurhash3_x64_128;

fn test_iter(bytes: &[u8], seed: u64) -> Duration {
    return Duration::span(|| {
        black_box(murmurhash3_x64_128(bytes, seed));
    });
}

fn main() {
    println!("MurmurHash3 x64 128bit Speed Test");

    let mut total_duration = Duration::zero();
    let trials = 1500;
    let mut data = [0u8; 256 * 1024];

    for i in range(0, trials) {
        rand::thread_rng().fill_bytes(&mut data);

        total_duration = total_duration + test_iter(&data, i);
    }

    let ns = total_duration.num_nanoseconds().unwrap() as f64;
    let total_s = ns / 1_000_000_000.0;
    let total_b = (data.len() as u64) * trials;
    let total_mb = (total_b as f64) / (1024.0 * 1024.0);

    println!("Avg MB/s: {}", total_mb / total_s);
}
<commit_msg>Increase number of benchmarking trials to stabilize results<commit_after>#![feature(test)]
#![feature(core)]
#![feature(rand)]
#![feature(std_misc)]

extern crate murmurhash3;
extern crate test;

use std::time::duration::Duration;
use std::rand;
use std::rand::Rng;

use test::black_box;

use murmurhash3::murmurhash3_x64_128;

fn test_iter(bytes: &[u8], seed: u64) -> Duration {
    return Duration::span(|| {
        black_box(murmurhash3_x64_128(bytes, seed));
    });
}

fn main() {
    println!("MurmurHash3 x64 128bit Speed Test");

    let mut total_duration = Duration::zero();
    let trials = 10000;
    let mut data = [0u8; 256 * 1024];

    for i in range(0, trials) {
        rand::thread_rng().fill_bytes(&mut data);

        total_duration = total_duration + test_iter(&data, i);
    }

    let ns = total_duration.num_nanoseconds().unwrap() as f64;
    let total_s = ns / 1_000_000_000.0;
    let total_b = (data.len() as u64) * trials;
    let total_mb = (total_b as f64) / (1024.0 * 1024.0);

    println!("Avg MB/s: {}", total_mb / total_s);
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate winit;

#[cfg(windows)]
use winit::os::windows::WindowExt;

#[macro_use]
extern crate vulkano;

#[path = "support/teapot.rs"]
mod teapot;

use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::ptr;

mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/examples/teapot_vs.glsl")} }
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/examples/teapot_fs.glsl")} }

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    // TODO: for the moment the AMD driver crashes if you don't pass an ApplicationInfo, but in theory it's optional
    let app = vulkano::instance::ApplicationInfo { application_name: "test", application_version: 1, engine_name: "test", engine_version: 1 };
    let extensions = vulkano::instance::InstanceExtensions {
        khr_surface: true,
        khr_swapchain: true,
        khr_win32_surface: true,
        .. vulkano::instance::InstanceExtensions::none()
    };
    let instance = vulkano::instance::Instance::new(Some(&app), &extensions, &["VK_LAYER_LUNARG_standard_validation"]).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let window = winit::WindowBuilder::new().build().unwrap();
    let surface = unsafe { vulkano::swapchain::Surface::from_hwnd(&instance, ptr::null() as *const () /* FIXME */, window.get_hwnd()).unwrap() };

    let queue = physical.queue_families().find(|q| q.supports_graphics() &&
                                                   surface.is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
    };

    let (device, queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
                                                        &device_ext, &["VK_LAYER_LUNARG_standard_validation"], [(queue, 0.5)].iter().cloned())
                                                                .expect("failed to create device");
    let queue = queues.into_iter().next().unwrap();

    let (swapchain, images) = {
        let caps = surface.get_capabilities(&physical).expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
        let present = caps.present_modes[0];
        let usage = caps.supported_usage_flags;

        vulkano::swapchain::Swapchain::new(&device, &surface, 3,
                                           vulkano::format::B8G8R8A8Srgb, dimensions, 1,
                                           &usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           vulkano::swapchain::CompositeAlpha::Opaque,
                                           present, true).expect("failed to create swapchain")
    };

    let cb_pool = vulkano::command_buffer::CommandBufferPool::new(&device, &queue.family())
                                                  .expect("failed to create command buffer pool");

    let depth_buffer = vulkano::image::Image::<vulkano::image::Type2d, _, _>::new(&device, &vulkano::image::Usage::all(),
                                                  vulkano::memory::DeviceLocal, &queue,
                                                  vulkano::format::D16Unorm, images[0].dimensions(), (), 1).unwrap();
    let depth_buffer = depth_buffer.transition(vulkano::image::Layout::DepthStencilAttachmentOptimal, &cb_pool, &queue).unwrap();
    let depth_buffer = vulkano::image::ImageView::new(&depth_buffer).expect("failed to create image view");

    let vertex_buffer = vulkano::buffer::Buffer
                               ::array(&device, teapot::VERTICES.len(),
                                       &vulkano::buffer::Usage::all(),
                                       vulkano::memory::HostVisible, &queue)
                                       .expect("failed to create buffer");

    {
        let mut mapping = vertex_buffer.try_write().unwrap();
        for (o, i) in mapping.iter_mut().zip(teapot::VERTICES.iter()) {
            *o = *i;
        }
    }

    let normals_buffer = vulkano::buffer::Buffer
                                ::array(&device, teapot::NORMALS.len(),
                                        &vulkano::buffer::Usage::all(),
                                        vulkano::memory::HostVisible, &queue)
                                        .expect("failed to create buffer");

    {
        let mut mapping = normals_buffer.try_write().unwrap();
        for (o, i) in mapping.iter_mut().zip(teapot::NORMALS.iter()) {
            *o = *i;
        }
    }

    let index_buffer = vulkano::buffer::Buffer
                              ::array(&device, teapot::INDICES.len(),
                                      &vulkano::buffer::Usage::all(),
                                      vulkano::memory::HostVisible, &queue)
                                      .expect("failed to create buffer");

    {
        let mut mapping = index_buffer.try_write().unwrap();
        for (o, i) in mapping.iter_mut().zip(teapot::INDICES.iter()) {
            *o = *i;
        }
    }

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let proj = cgmath::perspective(cgmath::rad(3.141592 / 2.0), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::Buffer::<vs::ty::Data, _>
                               ::new(&device, &vulkano::buffer::Usage::all(),
                                     vulkano::memory::HostVisible, &queue)
                               .expect("failed to create buffer");
    {
        let mut mapping = uniform_buffer.try_write().unwrap();
        mapping.worldview = (view * scale).into();
        mapping.proj = proj.into();
    }

    let vs = vs::Shader::load(&device).expect("failed to create shader module");
    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    let images = images.into_iter().map(|image| {
        let image = image.transition(vulkano::image::Layout::PresentSrc, &cb_pool,
                                     &queue).unwrap();
        vulkano::image::ImageView::new(&image).expect("failed to create image view")
    }).collect::<Vec<_>>();

    mod renderpass {
        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: B8G8R8A8Srgb,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: D16Unorm,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        }
    }

    let renderpass = vulkano::framebuffer::RenderPass::new(&device, renderpass::Layout).unwrap();

    let descriptor_pool = vulkano::descriptor_set::DescriptorPool::new(&device).unwrap();
    let descriptor_set_layout = vulkano::descriptor_set::DescriptorSetLayout::new(&device, vs::Set0).unwrap();

    mod pipeline_layout { pipeline_from_sets!(::vs::Set0); }
    let pipeline_layout = vulkano::descriptor_set::PipelineLayout::new(&device, pipeline_layout::Layout, (descriptor_set_layout.clone(),)).unwrap();
    let set = vulkano::descriptor_set::DescriptorSet::new(&descriptor_pool, &descriptor_set_layout,
                                                          uniform_buffer.clone() as std::sync::Arc<_>).unwrap();

    let pipeline = {
        let ia = vulkano::pipeline::input_assembly::InputAssembly::triangle_list();
        let raster = Default::default();
        let ms = vulkano::pipeline::multisample::Multisample::disabled();
        let blend = vulkano::pipeline::blend::Blend {
            logic_op: None,
            blend_constants: Some([0.0; 4]),
        };

        let viewports = vulkano::pipeline::viewport::ViewportsState::Fixed {
            data: vec![(
                vulkano::pipeline::viewport::Viewport {
                    origin: [0.0, 0.0],
                    dimensions: [1244.0, 699.0],
                    depth_range: 0.0 .. 1.0
                },
                vulkano::pipeline::viewport::Scissor {
                    origin: [0, 0],
                    dimensions: [1244, 699],
                }
            )],
        };

        vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::vertex::TwoBuffersDefinition::new(), &vs.main_entry_point(), &ia, &viewports,
                                                 &raster, &ms, &blend, &fs.main_entry_point(),
                                                 &pipeline_layout, vulkano::framebuffer::Subpass::from(&renderpass, 0).unwrap())
                                                 .unwrap()
    };

    let framebuffers = images.iter().map(|image| {
        vulkano::framebuffer::Framebuffer::new(&renderpass, (1244, 699, 1), (image.clone() as std::sync::Arc<_>, depth_buffer.clone() as std::sync::Arc<_>)).unwrap()
    }).collect::<Vec<_>>();

    let command_buffers = framebuffers.iter().map(|framebuffer| {
        vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&cb_pool).unwrap()
            .draw_inline(&renderpass, &framebuffer, ([0.0, 0.0, 1.0, 1.0], 1.0))
            .draw_indexed(&pipeline, (&vertex_buffer, &normals_buffer), &index_buffer, &vulkano::command_buffer::DynamicState::none(), set.clone())
            .draw_end()
            .build().unwrap()
    }).collect::<Vec<_>>();

    let mut submissions: Vec<vulkano::command_buffer::Submission> = Vec::new();

    loop {
        submissions.retain(|s| !s.destroying_would_block());

        let image_num = swapchain.acquire_next_image(1000000).unwrap();
        submissions.push(vulkano::command_buffer::submit(&command_buffers[image_num], &queue).unwrap());
        swapchain.present(&queue, image_num).unwrap();

        for ev in window.poll_events() {
            match ev {
                winit::Event::Closed => break,
                _ => ()
            }
        }
    }
}
<commit_msg>Don't require the SDK layer in the teapot example<commit_after>extern crate cgmath;
extern crate winit;

#[cfg(windows)]
use winit::os::windows::WindowExt;

#[macro_use]
extern crate vulkano;

#[path = "support/teapot.rs"]
mod teapot;

use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::ptr;

mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/examples/teapot_vs.glsl")} }
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/examples/teapot_fs.glsl")} }

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    // TODO: for the moment the AMD driver crashes if you don't pass an ApplicationInfo, but in theory it's optional
    let app = vulkano::instance::ApplicationInfo { application_name: "test", application_version: 1, engine_name: "test", engine_version: 1 };
    let extensions = vulkano::instance::InstanceExtensions {
        khr_surface: true,
        khr_swapchain: true,
        khr_win32_surface: true,
        .. vulkano::instance::InstanceExtensions::none()
    };
    let instance = vulkano::instance::Instance::new(Some(&app), &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let window = winit::WindowBuilder::new().build().unwrap();
    let surface = unsafe { vulkano::swapchain::Surface::from_hwnd(&instance, ptr::null() as *const () /* FIXME */, window.get_hwnd()).unwrap() };

    let queue = physical.queue_families().find(|q| q.supports_graphics() &&
                                                   surface.is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
    };

    let (device, queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
                                                        &device_ext, None, [(queue, 0.5)].iter().cloned())
                                                                .expect("failed to create device");
    let queue = queues.into_iter().next().unwrap();

    let (swapchain, images) = {
        let caps = surface.get_capabilities(&physical).expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
        let present = caps.present_modes[0];
        let usage = caps.supported_usage_flags;

        vulkano::swapchain::Swapchain::new(&device, &surface, 3,
                                           vulkano::format::B8G8R8A8Srgb, dimensions, 1,
                                           &usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           vulkano::swapchain::CompositeAlpha::Opaque,
                                           present, true).expect("failed to create swapchain")
    };

    let cb_pool = vulkano::command_buffer::CommandBufferPool::new(&device, &queue.family())
                                                  .expect("failed to create command buffer pool");

    let depth_buffer = vulkano::image::Image::<vulkano::image::Type2d, _, _>::new(&device, &vulkano::image::Usage::all(),
                                                  vulkano::memory::DeviceLocal, &queue,
                                                  vulkano::format::D16Unorm, images[0].dimensions(), (), 1).unwrap();
    let depth_buffer = depth_buffer.transition(vulkano::image::Layout::DepthStencilAttachmentOptimal, &cb_pool, &queue).unwrap();
    let depth_buffer = vulkano::image::ImageView::new(&depth_buffer).expect("failed to create image view");

    let vertex_buffer = vulkano::buffer::Buffer
                               ::array(&device, teapot::VERTICES.len(),
                                       &vulkano::buffer::Usage::all(),
                                       vulkano::memory::HostVisible, &queue)
                                       .expect("failed to create buffer");

    {
        let mut mapping = vertex_buffer.try_write().unwrap();
        for (o, i) in mapping.iter_mut().zip(teapot::VERTICES.iter()) {
            *o = *i;
        }
    }

    let normals_buffer = vulkano::buffer::Buffer
                                ::array(&device, teapot::NORMALS.len(),
                                        &vulkano::buffer::Usage::all(),
                                        vulkano::memory::HostVisible, &queue)
                                        .expect("failed to create buffer");

    {
        let mut mapping = normals_buffer.try_write().unwrap();
        for (o, i) in mapping.iter_mut().zip(teapot::NORMALS.iter()) {
            *o = *i;
        }
    }

    let index_buffer = vulkano::buffer::Buffer
                              ::array(&device, teapot::INDICES.len(),
                                      &vulkano::buffer::Usage::all(),
                                      vulkano::memory::HostVisible, &queue)
                                      .expect("failed to create buffer");

    {
        let mut mapping = index_buffer.try_write().unwrap();
        for (o, i) in mapping.iter_mut().zip(teapot::INDICES.iter()) {
            *o = *i;
        }
    }

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let proj = cgmath::perspective(cgmath::rad(3.141592 / 2.0), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::Buffer::<vs::ty::Data, _>
                               ::new(&device, &vulkano::buffer::Usage::all(),
                                     vulkano::memory::HostVisible, &queue)
                               .expect("failed to create buffer");
    {
        let mut mapping = uniform_buffer.try_write().unwrap();
        mapping.worldview = (view * scale).into();
        mapping.proj = proj.into();
    }

    let vs = vs::Shader::load(&device).expect("failed to create shader module");
    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    let images = images.into_iter().map(|image| {
        let image = image.transition(vulkano::image::Layout::PresentSrc, &cb_pool,
                                     &queue).unwrap();
        vulkano::image::ImageView::new(&image).expect("failed to create image view")
    }).collect::<Vec<_>>();

    mod renderpass {
        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: B8G8R8A8Srgb,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: D16Unorm,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        }
    }

    let renderpass = vulkano::framebuffer::RenderPass::new(&device, renderpass::Layout).unwrap();

    let descriptor_pool = vulkano::descriptor_set::DescriptorPool::new(&device).unwrap();
    let descriptor_set_layout = vulkano::descriptor_set::DescriptorSetLayout::new(&device, vs::Set0).unwrap();

    mod pipeline_layout { pipeline_from_sets!(::vs::Set0); }
    let pipeline_layout = vulkano::descriptor_set::PipelineLayout::new(&device, pipeline_layout::Layout, (descriptor_set_layout.clone(),)).unwrap();
    let set = vulkano::descriptor_set::DescriptorSet::new(&descriptor_pool, &descriptor_set_layout,
                                                          uniform_buffer.clone() as std::sync::Arc<_>).unwrap();

    let pipeline = {
        let ia = vulkano::pipeline::input_assembly::InputAssembly::triangle_list();
        let raster = Default::default();
        let ms = vulkano::pipeline::multisample::Multisample::disabled();
        let blend = vulkano::pipeline::blend::Blend {
            logic_op: None,
            blend_constants: Some([0.0; 4]),
        };

        let viewports = vulkano::pipeline::viewport::ViewportsState::Fixed {
            data: vec![(
                vulkano::pipeline::viewport::Viewport {
                    origin: [0.0, 0.0],
                    dimensions: [1244.0, 699.0],
                    depth_range: 0.0 .. 1.0
                },
                vulkano::pipeline::viewport::Scissor {
                    origin: [0, 0],
                    dimensions: [1244, 699],
                }
            )],
        };

        vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::vertex::TwoBuffersDefinition::new(), &vs.main_entry_point(), &ia, &viewports,
                                                 &raster, &ms, &blend, &fs.main_entry_point(),
                                                 &pipeline_layout, vulkano::framebuffer::Subpass::from(&renderpass, 0).unwrap())
                                                 .unwrap()
    };

    let framebuffers = images.iter().map(|image| {
        vulkano::framebuffer::Framebuffer::new(&renderpass, (1244, 699, 1), (image.clone() as std::sync::Arc<_>, depth_buffer.clone() as std::sync::Arc<_>)).unwrap()
    }).collect::<Vec<_>>();

    let command_buffers = framebuffers.iter().map(|framebuffer| {
        vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&cb_pool).unwrap()
            .draw_inline(&renderpass, &framebuffer, ([0.0, 0.0, 1.0, 1.0], 1.0))
            .draw_indexed(&pipeline, (&vertex_buffer, &normals_buffer), &index_buffer, &vulkano::command_buffer::DynamicState::none(), set.clone())
            .draw_end()
            .build().unwrap()
    }).collect::<Vec<_>>();

    let mut submissions: Vec<vulkano::command_buffer::Submission> = Vec::new();

    loop {
        submissions.retain(|s| !s.destroying_would_block());

        let image_num = swapchain.acquire_next_image(1000000).unwrap();
        submissions.push(vulkano::command_buffer::submit(&command_buffers[image_num], &queue).unwrap());
        swapchain.present(&queue, image_num).unwrap();

        for ev in window.poll_events() {
            match ev {
                winit::Event::Closed => break,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate lz4;

use std::env;
use std::fmt::{Display, Formatter};
use std::fs;
use std::fs::{File, PathExt, OpenOptions};
use std::io::{Error, ErrorKind, Read, Write, Seek, SeekFrom};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::{Hasher, SipHasher};
use std::path::{Path, PathBuf};

use super::compiler::OutputInfo;
use super::utils::hash_write_stream;
use super::utils::DEFAULT_BUF_SIZE;
use super::io::binary::*;

const HEADER: &'static [u8] = b"OBCF\x00\x02";
const FOOTER: &'static [u8] = b"END\x00";
const SUFFIX: &'static str = ".lz4";

#[derive(Debug)]
pub enum CacheError {
	InvalidHeader(PathBuf),
	InvalidFooter(PathBuf),
	PackedFilesMismatch(PathBuf),
	MutexError(String),
}

impl Display for CacheError {
	fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
		match self {
			&CacheError::InvalidHeader(ref path) => write!(f, "invalid cache file header: {}", path.display()),
			&CacheError::InvalidFooter(ref path) => write!(f, "invalid cache file footer: {}", path.display()),
			&CacheError::PackedFilesMismatch(ref path) => write!(f, "unexpected count of packed cached files: {}", path.display()),
			&CacheError::MutexError(ref message) => write!(f, "mutex error: {}", message),
		}
	}
}

impl ::std::error::Error for CacheError {
	fn description(&self) -> &str {
		match self {
			&CacheError::InvalidHeader(_) => "invalid cache file header",
			&CacheError::InvalidFooter(_) => "invalid cache file footer",
			&CacheError::PackedFilesMismatch(_) => "unexpected count of packed cached files",
			&CacheError::MutexError(_) => "mutex error",
		}
	}

	fn cause(&self) -> Option<&::std::error::Error> {
		None
	}
}

struct FileHash {
	hash: String,
	size: u64,
	modified: u64,
}

#[derive(Clone)]
pub struct Cache {
	file_hash: Arc<Mutex<HashMap<PathBuf, Arc<Mutex<Option<FileHash>>>>>>,
	cache_dir: PathBuf
}

struct CacheFile {
	path: PathBuf,
	size: u64,
	accessed: u64,
}

impl Cache {
	pub fn new() -> Self {
		let cache_dir = match env::var("OCTOBUILD_CACHE") {
			Ok(value) => Path::new(&value).to_path_buf(),
			Err(_) => env::home_dir().unwrap().join(".octobuild").join("cache")
		};
		Cache {
			file_hash: Arc::new(Mutex::new(HashMap::new())),
			cache_dir: cache_dir
		}
	}

	pub fn run_cached<F: Fn()->Result<OutputInfo, Error>>(&self, params: &str, inputs: &Vec<PathBuf>, outputs: &Vec<PathBuf>, worker: F) -> Result<OutputInfo, Error> {
		let hash = try! (self.generate_hash(params, inputs));
		let path = self.cache_dir.join(&hash[0..2]).join(&(hash[2..].to_string() + SUFFIX));
		// Try to read data from cache.
		match read_cache(&path, outputs) {
			Ok(output) => {return Ok(output)}
			Err(_) => {}
		}
		// Run task and save result to cache.
		let output = try !(worker());
		try !(write_cache(&path, outputs, &output));
		Ok(output)
	}

	pub fn cleanup(&self, max_cache_size: u64) -> Result<(), Error> {
		let mut files: Vec<CacheFile> = Vec::new();
		for item in try! (fs::walk_dir(&self.cache_dir)) {
			let path = try! (item).path();
			if path.to_str().map_or(false, |v| v.ends_with(SUFFIX)) {
				let attr = try! (fs::metadata(&path));
				if attr.is_file() {
					files.push(CacheFile {
						path: path,
						size: attr.len(),
						accessed: attr.modified(),
					});
				}
			}
		}
		files.sort_by(|a, b| b.accessed.cmp(&a.accessed));

		let mut cache_size: u64 = 0;
		for item in files.into_iter() {
			cache_size += item.size;
			if cache_size > max_cache_size {
				let _ = try!(fs::remove_file(&item.path));
			}
		}
		Ok(())
	}

	fn generate_hash(&self, params: &str, inputs: &Vec<PathBuf>) -> Result<String, Error> {
		let mut sip_hash = SipHasher::new();
		let hash: &mut Hasher = &mut sip_hash;
		// str
		hash.write(params.as_bytes());
		hash.write_u8(0);
		// inputs
		for input in inputs.iter() {
			let file_hash = try! (self.get_file_hash(input));
			hash.write(file_hash.as_bytes());
		}
		Ok(format!("{:016x}", hash.finish()))
	}

	pub fn get_file_hash(&self, path: &Path) -> Result<String, Error> {
		// Get/create lock for file entry.
		let hash_lock = match self.file_hash.lock() {
			Ok(mut map) => {
				match map.entry(path.to_path_buf()) {
					Entry::Occupied(entry) => entry.get().clone(),
					Entry::Vacant(entry) => entry.insert(Arc::new(Mutex::new(None))).clone()
				}
			}
			Err(e) => {
				return Err(Error::new(ErrorKind::Other, CacheError::MutexError(e.to_string())));
			}
		};
		// Get file hash.
		let result = match hash_lock.lock() { // rust: #22722
			Ok(mut hash_entry) => {
				// Validate entry, if exists.
				match *hash_entry {
					Some(ref value) => {
						let stat = try! (fs::metadata(path));
						if value.size == stat.len() && value.modified == stat.modified() {
							return Ok(value.hash.clone());
						}
					}
					None => {}
				}
				// Calculate hash value.
				let stat = try! (fs::metadata(path));
				let hash = try! (generate_file_hash(path));
				*hash_entry = Some(FileHash {
					hash: hash.clone(),
					size: stat.len(),
					modified: stat.modified(),
				});
				Ok(hash)
			}
			Err(e) => Err(Error::new(ErrorKind::Other, CacheError::MutexError(e.to_string())))
		};
		result
	}
}

fn generate_file_hash(path: &Path) -> Result<String, Error> {
	let mut hash = SipHasher::new();
	let mut file = try! (File::open(path));
	try! (hash_write_stream(&mut hash, &mut file));
	Ok(format!("{:016x}", hash.finish()))
}

fn write_cache(path: &Path, paths: &Vec<PathBuf>, output: &OutputInfo) -> Result<(), Error> {
	if !output.success() {
		return Ok(());
	}
	match path.parent() {
		Some(parent) => try! (fs::create_dir_all(&parent)),
		None => ()
	}

	fn write_cache_compressed<W: Write>(write: W, paths: &Vec<PathBuf>, output: &OutputInfo) -> Result<(), Error> {
		let mut stream = try! (lz4::Encoder::new(write, 1));
		try! (write_cache_inner(&mut stream, paths, output));
		match stream.finish() {
			(_, result) => result
		}
	}

	fn write_cache_inner(stream: &mut Write, paths: &Vec<PathBuf>, output: &OutputInfo) -> Result<(), Error> {
		try! (stream.write_all(HEADER));
		try! (write_usize(stream, paths.len()));
		let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
		for path in paths.iter() {
			let mut file = try! (File::open(path));
			loop {
				let size = try! (file.read(&mut buf));
				if size <= 0 {
					break;
				}
				try! (write_usize(stream, size));
				try! (stream.write_all(&buf[0..size]));
			}
			try! (write_usize(stream, 0));
		}
		try! (write_output(stream, output));
		try! (stream.write_all(FOOTER));
		Ok(())
	}

	match write_cache_compressed(try! (File::create(path)), paths, output) {
		Err(e) => {
			let raw_path = path.with_extension("blk");
			write_cache_inner(&mut BlockWrite(try! (File::create(&raw_path))), paths, output);
			println!("COMPRESSION FAILED. PLEASE SEND FILE TO DEVELOPER: {:?}", raw_path);
			return Err(e);
		}
		Ok(v) => Ok(v),
	}
}

struct BlockWrite<W: Write> (W);

impl<W: Write> Write for BlockWrite<W> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
    	try! (write_usize(&mut self.0, buf.len()));
    	self.0.write(buf)
    }

    fn flush(&mut self) -> Result<(), Error> {
    	self.0.flush()
    }
}

fn read_cache(path: &Path, paths: &Vec<PathBuf>) -> Result<OutputInfo, Error> {
	let mut file = try! (OpenOptions::new().read(true).write(true).open(Path::new(path)));
	try! (file.write(&[4]));
	try! (file.seek(SeekFrom::Start(0)));
	let mut stream = try! (lz4::Decoder::new (file));
	if try! (read_exact(&mut stream, HEADER.len())) != HEADER {
		return Err(Error::new(ErrorKind::InvalidInput, CacheError::InvalidHeader(path.to_path_buf())));
	}
	if try! (read_usize(&mut stream)) != paths.len() {
		return Err(Error::new(ErrorKind::InvalidInput, CacheError::PackedFilesMismatch(path.to_path_buf())));
	}
	for path in paths.iter() {
		let mut file = try! (File::create(path));
		loop {
			let size = try! (read_usize(&mut stream));
			if size == 0 {break;}
			let block = try! (read_exact(&mut stream, size));
			try! (file.write_all(&block));
		}
	}
	let output = try! (read_output(&mut stream));
	if try! (read_exact(&mut stream, FOOTER.len())) != FOOTER {
		return Err(Error::new(ErrorKind::InvalidInput, CacheError::InvalidFooter(path.to_path_buf())));
	}
	Ok(output)
}

fn write_blob(stream: &mut Write, blob: &[u8]) -> Result<(), Error> {
	try! (write_usize(stream, blob.len()));
	try! (stream.write_all(blob));
	Ok(())
}

fn read_blob(stream: &mut Read) -> Result<Vec<u8>, Error> {
	let size = try! (read_usize(stream));
	read_exact(stream, size)
}

fn write_output(stream: &mut Write, output: &OutputInfo) -> Result<(), Error> {
	try! (write_blob(stream, &output.stdout));
	try! (write_blob(stream, &output.stderr));
	Ok(())
}

fn read_output(stream: &mut Read) -> Result<OutputInfo, Error> {
	let stdout = try! (read_blob(stream));
	let stderr = try! (read_blob(stream));
	Ok(OutputInfo {
		status: Some(0),
		stdout: stdout,
		stderr: stderr,
	})
}
<commit_msg>Add version number to diagnostic file<commit_after>extern crate lz4;

use std::env;
use std::fmt::{Display, Formatter};
use std::fs;
use std::fs::{File, PathExt, OpenOptions};
use std::io::{Error, ErrorKind, Read, Write, Seek, SeekFrom};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::{Hasher, SipHasher};
use std::path::{Path, PathBuf};

use super::compiler::OutputInfo;
use super::utils::hash_write_stream;
use super::utils::DEFAULT_BUF_SIZE;
use super::io::binary::*;
use super::version;

const HEADER: &'static [u8] = b"OBCF\x00\x02";
const FOOTER: &'static [u8] = b"END\x00";
const SUFFIX: &'static str = ".lz4";

#[derive(Debug)]
pub enum CacheError {
	InvalidHeader(PathBuf),
	InvalidFooter(PathBuf),
	PackedFilesMismatch(PathBuf),
	MutexError(String),
}

impl Display for CacheError {
	fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
		match self {
			&CacheError::InvalidHeader(ref path) => write!(f, "invalid cache file header: {}", path.display()),
			&CacheError::InvalidFooter(ref path) => write!(f, "invalid cache file footer: {}", path.display()),
			&CacheError::PackedFilesMismatch(ref path) => write!(f, "unexpected count of packed cached files: {}", path.display()),
			&CacheError::MutexError(ref message) => write!(f, "mutex error: {}", message),
		}
	}
}

impl ::std::error::Error for CacheError {
	fn description(&self) -> &str {
		match self {
			&CacheError::InvalidHeader(_) => "invalid cache file header",
			&CacheError::InvalidFooter(_) => "invalid cache file footer",
			&CacheError::PackedFilesMismatch(_) => "unexpected count of packed cached files",
			&CacheError::MutexError(_) => "mutex error",
		}
	}

	fn cause(&self) -> Option<&::std::error::Error> {
		None
	}
}

struct FileHash {
	hash: String,
	size: u64,
	modified: u64,
}

#[derive(Clone)]
pub struct Cache {
	file_hash: Arc<Mutex<HashMap<PathBuf, Arc<Mutex<Option<FileHash>>>>>>,
	cache_dir: PathBuf
}

struct CacheFile {
	path: PathBuf,
	size: u64,
	accessed: u64,
}

impl Cache {
	pub fn new() -> Self {
		let cache_dir = match env::var("OCTOBUILD_CACHE") {
			Ok(value) => Path::new(&value).to_path_buf(),
			Err(_) => env::home_dir().unwrap().join(".octobuild").join("cache")
		};
		Cache {
			file_hash: Arc::new(Mutex::new(HashMap::new())),
			cache_dir: cache_dir
		}
	}

	pub fn run_cached<F: Fn()->Result<OutputInfo, Error>>(&self, params: &str, inputs: &Vec<PathBuf>, outputs: &Vec<PathBuf>, worker: F) -> Result<OutputInfo, Error> {
		let hash = try! (self.generate_hash(params, inputs));
		let path = self.cache_dir.join(&hash[0..2]).join(&(hash[2..].to_string() + SUFFIX));
		// Try to read data from cache.
		match read_cache(&path, outputs) {
			Ok(output) => {return Ok(output)}
			Err(_) => {}
		}
		// Run task and save result to cache.
		let output = try !(worker());
		try !(write_cache(&path, outputs, &output));
		Ok(output)
	}

	pub fn cleanup(&self, max_cache_size: u64) -> Result<(), Error> {
		let mut files: Vec<CacheFile> = Vec::new();
		for item in try! (fs::walk_dir(&self.cache_dir)) {
			let path = try! (item).path();
			if path.to_str().map_or(false, |v| v.ends_with(SUFFIX)) {
				let attr = try! (fs::metadata(&path));
				if attr.is_file() {
					files.push(CacheFile {
						path: path,
						size: attr.len(),
						accessed: attr.modified(),
					});
				}
			}
		}
		files.sort_by(|a, b| b.accessed.cmp(&a.accessed));

		let mut cache_size: u64 = 0;
		for item in files.into_iter() {
			cache_size += item.size;
			if cache_size > max_cache_size {
				let _ = try!(fs::remove_file(&item.path));
			}
		}
		Ok(())
	}

	fn generate_hash(&self, params: &str, inputs: &Vec<PathBuf>) -> Result<String, Error> {
		let mut sip_hash = SipHasher::new();
		let hash: &mut Hasher = &mut sip_hash;
		// str
		hash.write(params.as_bytes());
		hash.write_u8(0);
		// inputs
		for input in inputs.iter() {
			let file_hash = try! (self.get_file_hash(input));
			hash.write(file_hash.as_bytes());
		}
		Ok(format!("{:016x}", hash.finish()))
	}

	pub fn get_file_hash(&self, path: &Path) -> Result<String, Error> {
		// Get/create lock for file entry.
		let hash_lock = match self.file_hash.lock() {
			Ok(mut map) => {
				match map.entry(path.to_path_buf()) {
					Entry::Occupied(entry) => entry.get().clone(),
					Entry::Vacant(entry) => entry.insert(Arc::new(Mutex::new(None))).clone()
				}
			}
			Err(e) => {
				return Err(Error::new(ErrorKind::Other, CacheError::MutexError(e.to_string())));
			}
		};
		// Get file hash.
		let result = match hash_lock.lock() { // rust: #22722
			Ok(mut hash_entry) => {
				// Validate entry, if exists.
				match *hash_entry {
					Some(ref value) => {
						let stat = try! (fs::metadata(path));
						if value.size == stat.len() && value.modified == stat.modified() {
							return Ok(value.hash.clone());
						}
					}
					None => {}
				}
				// Calculate hash value.
				let stat = try! (fs::metadata(path));
				let hash = try! (generate_file_hash(path));
				*hash_entry = Some(FileHash {
					hash: hash.clone(),
					size: stat.len(),
					modified: stat.modified(),
				});
				Ok(hash)
			}
			Err(e) => Err(Error::new(ErrorKind::Other, CacheError::MutexError(e.to_string())))
		};
		result
	}
}

fn generate_file_hash(path: &Path) -> Result<String, Error> {
	let mut hash = SipHasher::new();
	let mut file = try! (File::open(path));
	try! (hash_write_stream(&mut hash, &mut file));
	Ok(format!("{:016x}", hash.finish()))
}

fn write_cache(path: &Path, paths: &Vec<PathBuf>, output: &OutputInfo) -> Result<(), Error> {
	if !output.success() {
		return Ok(());
	}
	match path.parent() {
		Some(parent) => try! (fs::create_dir_all(&parent)),
		None => ()
	}

	fn write_cache_compressed<W: Write>(write: W, paths: &Vec<PathBuf>, output: &OutputInfo) -> Result<(), Error> {
		let mut stream = try! (lz4::Encoder::new(write, 1));
		try! (write_cache_inner(&mut stream, paths, output));
		match stream.finish() {
			(_, result) => result
		}
	}

	fn write_cache_inner(stream: &mut Write, paths: &Vec<PathBuf>, output: &OutputInfo) -> Result<(), Error> {
		try! (stream.write_all(HEADER));
		try! (write_usize(stream, paths.len()));
		let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
		for path in paths.iter() {
			let mut file = try! (File::open(path));
			loop {
				let size = try! (file.read(&mut buf));
				if size <= 0 {
					break;
				}
				try! (write_usize(stream, size));
				try! (stream.write_all(&buf[0..size]));
			}
			try! (write_usize(stream, 0));
		}
		try! (write_output(stream, output));
		try! (stream.write_all(FOOTER));
		Ok(())
	}

	match write_cache_compressed(try! (File::create(path)), paths, output) {
		Err(e) => {
			let raw_path = path.with_extension("blk");
			let mut stream = BlockWrite(try! (File::create(&raw_path)));
			let _ = stream.write(&version::full_version().into_bytes());
			let _ = write_cache_inner(&mut stream, paths, output);
			println!("COMPRESSION FAILED. PLEASE SEND FILE TO DEVELOPER: {:?}", raw_path);
			return Err(e);
		}
		Ok(v) => Ok(v),
	}
}

struct BlockWrite<W: Write> (W);

impl<W: Write> Write for BlockWrite<W> {
	fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
		try! (write_usize(&mut self.0, buf.len()));
		self.0.write(buf)
	}

	fn flush(&mut self) -> Result<(), Error> {
		self.0.flush()
	}
}

fn read_cache(path: &Path, paths: &Vec<PathBuf>) -> Result<OutputInfo, Error> {
	let mut file = try! (OpenOptions::new().read(true).write(true).open(Path::new(path)));
	try! (file.write(&[4]));
	try! (file.seek(SeekFrom::Start(0)));
	let mut stream = try! (lz4::Decoder::new (file));
	if try! (read_exact(&mut stream, HEADER.len())) != HEADER {
		return Err(Error::new(ErrorKind::InvalidInput, CacheError::InvalidHeader(path.to_path_buf())));
	}
	if try! (read_usize(&mut stream)) != paths.len() {
		return Err(Error::new(ErrorKind::InvalidInput, CacheError::PackedFilesMismatch(path.to_path_buf())));
	}
	for path in paths.iter() {
		let mut file = try! (File::create(path));
		loop {
			let size = try! (read_usize(&mut stream));
			if size == 0 {break;}
			let block = try! (read_exact(&mut stream, size));
			try! (file.write_all(&block));
		}
	}
	let output = try! (read_output(&mut stream));
	if try! (read_exact(&mut stream, FOOTER.len())) != FOOTER {
		return Err(Error::new(ErrorKind::InvalidInput, CacheError::InvalidFooter(path.to_path_buf())));
	}
	Ok(output)
}

fn write_blob(stream: &mut Write, blob: &[u8]) -> Result<(), Error> {
	try! (write_usize(stream, blob.len()));
	try! (stream.write_all(blob));
	Ok(())
}

fn read_blob(stream: &mut Read) -> Result<Vec<u8>, Error> {
	let size = try! (read_usize(stream));
	read_exact(stream, size)
}

fn write_output(stream: &mut Write, output: &OutputInfo) -> Result<(), Error> {
	try! (write_blob(stream, &output.stdout));
	try! (write_blob(stream, &output.stderr));
	Ok(())
}

fn read_output(stream: &mut Read) -> Result<OutputInfo, Error> {
	let stdout = try! (read_blob(stream));
	let stderr = try! (read_blob(stream));
	Ok(OutputInfo {
		status: Some(0),
		stdout: stdout,
		stderr: stderr,
	})
}
<|endoftext|>