<commit_before>// This test case tests the incremental compilation hash (ICH) implementation
// for `while` loops.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// build-pass (FIXME(62277): could be check-pass?)
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Change loop body ------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_loop_body() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_loop_body() {
    let mut _x = 0;
    while true {
        _x = 2;
        break;
    }
}

// Change loop body ------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_loop_condition() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_loop_condition() {
    let mut _x = 0;
    while false {
        _x = 1;
        break;
    }
}

// Add break -------------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_break() {
    let mut _x = 0;
    while true {
        _x = 1;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")]
#[rustc_clean(cfg="cfail3")]
pub fn add_break() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

// Add loop label --------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_loop_label() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_loop_label() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        break;
    }
}

// Add loop label to break -----------------------------------------------------
#[cfg(cfail1)]
pub fn add_loop_label_to_break() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_loop_label_to_break() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        break 'label;
    }
}

// Change break label ----------------------------------------------------------
#[cfg(cfail1)]
pub fn change_break_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            break 'inner;
        }
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_break_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            break 'outer;
        }
    }
}

// Add loop label to continue --------------------------------------------------
#[cfg(cfail1)]
pub fn add_loop_label_to_continue() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        continue;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_loop_label_to_continue() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        continue 'label;
    }
}

// Change continue label ----------------------------------------------------------
#[cfg(cfail1)]
pub fn change_continue_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            continue 'inner;
        }
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
#[rustc_clean(cfg="cfail3")]
pub fn change_continue_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            continue 'outer;
        }
    }
}

// Change continue to break ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_continue_to_break() {
    let mut _x = 0;
    while true {
        _x = 1;
        continue;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_continue_to_break() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}
<commit_msg>Adjust incremental test while_loops.rs<commit_after>// This test case tests the incremental compilation hash (ICH) implementation
// for `while` loops.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// build-pass (FIXME(62277): could be check-pass?)
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Change loop body ------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_loop_body() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_loop_body() {
    let mut _x = 0;
    while true {
        _x = 2;
        break;
    }
}

// Change loop body ------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_loop_condition() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_loop_condition() {
    let mut _x = 0;
    while false {
        _x = 1;
        break;
    }
}

// Add break -------------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_break() {
    let mut _x = 0;
    while true {
        _x = 1;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")]
#[rustc_clean(cfg="cfail3")]
pub fn add_break() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

// Add loop label --------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_loop_label() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_loop_label() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        break;
    }
}

// Add loop label to break -----------------------------------------------------
#[cfg(cfail1)]
pub fn add_loop_label_to_break() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        break;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_loop_label_to_break() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        break 'label;
    }
}

// Change break label ----------------------------------------------------------
#[cfg(cfail1)]
pub fn change_break_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            break 'inner;
        }
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="typeck_tables_of, HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_break_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            break 'outer;
        }
    }
}

// Add loop label to continue --------------------------------------------------
#[cfg(cfail1)]
pub fn add_loop_label_to_continue() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        continue;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_loop_label_to_continue() {
    let mut _x = 0;
    'label: while true {
        _x = 1;
        continue 'label;
    }
}

// Change continue label ----------------------------------------------------------
#[cfg(cfail1)]
pub fn change_continue_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            continue 'inner;
        }
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="typeck_tables_of, HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_continue_label() {
    let mut _x = 0;
    'outer: while true {
        'inner: while true {
            _x = 1;
            continue 'outer;
        }
    }
}

// Change continue to break ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_continue_to_break() {
    let mut _x = 0;
    while true {
        _x = 1;
        continue;
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
pub fn change_continue_to_break() {
    let mut _x = 0;
    while true {
        _x = 1;
        break;
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::process;

#[macro_use]
extern crate log;

pub type Error = io::Error;
pub type Result<T> = io::Result<T>;

fn err_other<T>(s: &str) -> Result<T> {
    Err(Error::new(io::ErrorKind::Other, s.to_owned()))
}

/// `Protoc --lang_out...` args
#[derive(Default)]
pub struct Args<'a> {
    /// `LANG` part in `--LANG_out=...`
    pub lang: &'a str,
    /// `--LANG_out=...` param
    pub out_dir: &'a str,
    /// `--plugin` param. Not needed if plugin is in `$PATH`
    pub plugin: Option<&'a str>,
    /// `-I` args
    pub includes: &'a [&'a str],
    /// List of `.proto` files to compile
    pub input: &'a [&'a str],
}

/// `Protoc --descriptor_set_out...` args
#[derive(Debug)]
pub struct DescriptorSetOutArgs<'a> {
    /// `--file_descriptor_out=...` param
    pub out: &'a str,
    /// `-I` args
    pub includes: &'a [&'a str],
    /// List of `.proto` files to compile
    pub input: &'a [&'a str],
    /// `--include_imports`
    pub include_imports: bool,
}

/// Protoc command.
pub struct Protoc {
    exec: String,
}

impl Protoc {
    /// New `protoc` command from `$PATH`
    pub fn from_env_path() -> Protoc {
        Protoc {
            exec: "protoc".to_owned(),
        }
    }

    /// New `protoc` command from specified path
    pub fn from_path(path: &str) -> Protoc {
        Protoc {
            exec: path.to_owned(),
        }
    }

    /// Check `protoc` command found and valid
    pub fn check(&self) -> Result<()> {
        self.version().map(|_| ())
    }

    fn spawn(&self, cmd: &mut process::Command) -> io::Result<process::Child> {
        info!("spawning command {:?}", cmd);

        cmd.spawn()
            .map_err(|e| Error::new(e.kind(), format!("failed to spawn `{:?}`: {}", cmd, e)))
    }

    /// Obtain `protoc` version
    pub fn version(&self) -> Result<Version> {
        let child = self.spawn(
            process::Command::new(&self.exec)
                .stdin(process::Stdio::null())
                .stdout(process::Stdio::piped())
                .stderr(process::Stdio::piped())
                .args(&["--version"]),
        )?;

        let output = child.wait_with_output()?;
        if !output.status.success() {
            return err_other("protoc failed with error");
        }
        let output =
            String::from_utf8(output.stdout).map_err(|e| Error::new(io::ErrorKind::Other, e))?;
        let output = match output.lines().next() {
            None => return err_other("output is empty"),
            Some(line) => line,
        };
        let prefix = "libprotoc ";
        if !output.starts_with(prefix) {
            return err_other("output does not start with prefix");
        }
        let output = &output[prefix.len()..];
        if output.is_empty() {
            return err_other("version is empty");
        }
        let first = output.chars().next().unwrap();
        if !first.is_digit(10) {
            return err_other("version does not start with digit");
        }
        Ok(Version {
            version: output.to_owned(),
        })
    }

    /// Execute `protoc` command with given args, check it completed correctly.
    fn run_with_args(&self, args: Vec<String>) -> Result<()> {
        let mut cmd = process::Command::new(&self.exec);
        cmd.stdin(process::Stdio::null());
        cmd.args(args);

        let mut child = self.spawn(&mut cmd)?;

        if !child.wait()?.success() {
            return err_other("protoc exited with non-zero exit code");
        }

        Ok(())
    }

    /// Execute configured `protoc` with given args
    pub fn run(&self, args: Args) -> Result<()> {
        let mut cmd_args: Vec<String> = Vec::new();

        if args.out_dir.is_empty() {
            return err_other("out_dir is empty");
        }

        if args.lang.is_empty() {
            return err_other("lang is empty");
        }

        cmd_args.push(format!("--{}_out={}", args.lang, args.out_dir));

        if args.input.is_empty() {
            return err_other("input is empty");
        }

        cmd_args.extend(args.input.into_iter().map(|a| String::from(*a)));

        if let Some(plugin) = args.plugin {
            cmd_args.push(format!("--plugin={}", plugin));
        }

        for include in args.includes {
            cmd_args.push(format!("-I{}", include));
        }

        self.run_with_args(cmd_args)
    }

    /// Execute `protoc --descriptor_set_out=`
    pub fn write_descriptor_set(&self, args: DescriptorSetOutArgs) -> Result<()> {
        let mut cmd_args: Vec<String> = Vec::new();

        for include in args.includes {
            cmd_args.push(format!("-I{}", include));
        }

        if args.out.is_empty() {
            return err_other("out is empty");
        }

        cmd_args.push(format!("--descriptor_set_out={}", args.out));

        if args.include_imports {
            cmd_args.push("--include_imports".to_owned());
        }

        if args.input.is_empty() {
            return err_other("input is empty");
        }

        cmd_args.extend(args.input.into_iter().map(|a| String::from(*a)));

        self.run_with_args(cmd_args)
    }
}

/// Execute `protoc` found in `$PATH` with given args
pub fn run(args: Args) -> Result<()> {
    let protoc = Protoc::from_env_path();

    // First check with have good `protoc`
    protoc.check()?;

    protoc.run(args)
}

/// Protobuf (protoc) version.
pub struct Version {
    version: String,
}

impl Version {
    pub fn is_3(&self) -> bool {
        self.version.starts_with("3")
    }
}

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

    #[test]
    fn version() {
        Protoc::from_env_path().version().expect("version");
    }

}
<commit_msg>Better diagnostics of protoc failure<commit_after>use std::io;
use std::process;

#[macro_use]
extern crate log;

pub type Error = io::Error;
pub type Result<T> = io::Result<T>;

fn err_other<T>(s: &str) -> Result<T> {
    Err(Error::new(io::ErrorKind::Other, s.to_owned()))
}

/// `Protoc --lang_out...` args
#[derive(Default)]
pub struct Args<'a> {
    /// `LANG` part in `--LANG_out=...`
    pub lang: &'a str,
    /// `--LANG_out=...` param
    pub out_dir: &'a str,
    /// `--plugin` param. Not needed if plugin is in `$PATH`
    pub plugin: Option<&'a str>,
    /// `-I` args
    pub includes: &'a [&'a str],
    /// List of `.proto` files to compile
    pub input: &'a [&'a str],
}

/// `Protoc --descriptor_set_out...` args
#[derive(Debug)]
pub struct DescriptorSetOutArgs<'a> {
    /// `--file_descriptor_out=...` param
    pub out: &'a str,
    /// `-I` args
    pub includes: &'a [&'a str],
    /// List of `.proto` files to compile
    pub input: &'a [&'a str],
    /// `--include_imports`
    pub include_imports: bool,
}

/// Protoc command.
pub struct Protoc {
    exec: String,
}

impl Protoc {
    /// New `protoc` command from `$PATH`
    pub fn from_env_path() -> Protoc {
        Protoc {
            exec: "protoc".to_owned(),
        }
    }

    /// New `protoc` command from specified path
    pub fn from_path(path: &str) -> Protoc {
        Protoc {
            exec: path.to_owned(),
        }
    }

    /// Check `protoc` command found and valid
    pub fn check(&self) -> Result<()> {
        self.version().map(|_| ())
    }

    fn spawn(&self, cmd: &mut process::Command) -> io::Result<process::Child> {
        info!("spawning command {:?}", cmd);

        cmd.spawn()
            .map_err(|e| Error::new(e.kind(), format!("failed to spawn `{:?}`: {}", cmd, e)))
    }

    /// Obtain `protoc` version
    pub fn version(&self) -> Result<Version> {
        let child = self.spawn(
            process::Command::new(&self.exec)
                .stdin(process::Stdio::null())
                .stdout(process::Stdio::piped())
                .stderr(process::Stdio::piped())
                .args(&["--version"]),
        )?;

        let output = child.wait_with_output()?;
        if !output.status.success() {
            return err_other("protoc failed with error");
        }
        let output =
            String::from_utf8(output.stdout).map_err(|e| Error::new(io::ErrorKind::Other, e))?;
        let output = match output.lines().next() {
            None => return err_other("output is empty"),
            Some(line) => line,
        };
        let prefix = "libprotoc ";
        if !output.starts_with(prefix) {
            return err_other("output does not start with prefix");
        }
        let output = &output[prefix.len()..];
        if output.is_empty() {
            return err_other("version is empty");
        }
        let first = output.chars().next().unwrap();
        if !first.is_digit(10) {
            return err_other("version does not start with digit");
        }
        Ok(Version {
            version: output.to_owned(),
        })
    }

    /// Execute `protoc` command with given args, check it completed correctly.
    fn run_with_args(&self, args: Vec<String>) -> Result<()> {
        let mut cmd = process::Command::new(&self.exec);
        cmd.stdin(process::Stdio::null());
        cmd.args(args);

        let mut child = self.spawn(&mut cmd)?;

        if !child.wait()?.success() {
            return err_other(&format!("protoc ({:?}) exited with non-zero exit code", cmd));
        }

        Ok(())
    }

    /// Execute configured `protoc` with given args
    pub fn run(&self, args: Args) -> Result<()> {
        let mut cmd_args: Vec<String> = Vec::new();

        if args.out_dir.is_empty() {
            return err_other("out_dir is empty");
        }

        if args.lang.is_empty() {
            return err_other("lang is empty");
        }

        cmd_args.push(format!("--{}_out={}", args.lang, args.out_dir));

        if args.input.is_empty() {
            return err_other("input is empty");
        }

        cmd_args.extend(args.input.into_iter().map(|a| String::from(*a)));

        if let Some(plugin) = args.plugin {
            cmd_args.push(format!("--plugin={}", plugin));
        }

        for include in args.includes {
            cmd_args.push(format!("-I{}", include));
        }

        self.run_with_args(cmd_args)
    }

    /// Execute `protoc --descriptor_set_out=`
    pub fn write_descriptor_set(&self, args: DescriptorSetOutArgs) -> Result<()> {
        let mut cmd_args: Vec<String> = Vec::new();

        for include in args.includes {
            cmd_args.push(format!("-I{}", include));
        }

        if args.out.is_empty() {
            return err_other("out is empty");
        }

        cmd_args.push(format!("--descriptor_set_out={}", args.out));

        if args.include_imports {
            cmd_args.push("--include_imports".to_owned());
        }

        if args.input.is_empty() {
            return err_other("input is empty");
        }

        cmd_args.extend(args.input.into_iter().map(|a| String::from(*a)));

        self.run_with_args(cmd_args)
    }
}

/// Execute `protoc` found in `$PATH` with given args
pub fn run(args: Args) -> Result<()> {
    let protoc = Protoc::from_env_path();

    // First check with have good `protoc`
    protoc.check()?;

    protoc.run(args)
}

/// Protobuf (protoc) version.
pub struct Version {
    version: String,
}

impl Version {
    pub fn is_3(&self) -> bool {
        self.version.starts_with("3")
    }
}

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

    #[test]
    fn version() {
        Protoc::from_env_path().version().expect("version");
    }

}
<|endoftext|>


<commit_before>//! Synchronization primitives for Vulkan objects.
//!
//! In Vulkan, you have to manually ensure two things:
//!
//! - That a buffer or an image are not read and written simultaneously (similarly to the CPU).
//! - That writes to a buffer or an image are propagated to other queues by inserting memory
//!   barriers.
//!
//! But don't worry ; this is automatically enforced by this library (as long as you don't use
//! any unsafe function). See the `memory` module for more info.
//!
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;

use device::Device;
use device::Queue;
use OomError;
use Success;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

pub unsafe trait Resource {
    /// Returns in which queue family or families this resource can be used.
    fn sharing_mode(&self) -> &SharingMode;

    /// Returns true if the `gpu_access` function should be passed a fence.
    #[inline]
    fn requires_fence(&self) -> bool {
        true
    }

    /// Returns true if the `gpu_access` function should be passed a semaphore.
    #[inline]
    fn requires_semaphore(&self) -> bool {
        true
    }

    /// Instructs the resource that it is going to be used by the GPU soon in the future. The
    /// function should block if the memory is currently being accessed by the CPU.
    ///
    /// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
    /// be written.
    ///
    /// `queue` is the queue where the command buffer that accesses the memory will be submitted.
    /// If the `gpu_access` function submits something to that queue, it will thus be submitted
    /// beforehand. This behavior can be used for example to submit sparse binding commands.
    ///
    /// `fence` is a fence that will be signaled when this GPU access will stop. It should be
    /// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
    /// returned false, then this value will be `None`.
    ///
    /// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
    /// is intended to be returned later, in a follow-up call to `gpu_access`. If
    /// `requires_semaphore` returned false, then this value will be `None`.
    ///
    /// The function can return a semaphore which will be waited up by the GPU before the
    /// work starts.
    fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
                  semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>;
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SharingMode {
    Exclusive(u32),
    Concurrent(Vec<u32>),       // TODO: Vec is too expensive here
}

impl<'a> From<&'a Arc<Mutex<Queue>>> for SharingMode {
    #[inline]
    fn from(queue: &'a Arc<Mutex<Queue>>) -> SharingMode {
        let queue = queue.lock().unwrap();      // TODO: meh
        SharingMode::Exclusive(queue.family().id())
    }
}

impl<'a> From<&'a [&'a Arc<Mutex<Queue>>]> for SharingMode {
    #[inline]
    fn from(queues: &'a [&'a Arc<Mutex<Queue>>]) -> SharingMode {
        SharingMode::Concurrent(queues.iter().map(|queue| {
            let queue = queue.lock().unwrap();      // TODO: meh
            queue.family().id()
        }).collect())
    }
}

/// A fence is used to know when a command buffer submission has finished its execution.
///
/// When a command buffer accesses a ressource, you have to ensure that the CPU doesn't access
/// the same ressource simultaneously (except for concurrent reads). Therefore in order to know
/// when the CPU can access a ressource again, a fence has to be used.
pub struct Fence {
    device: Arc<Device>,
    fence: vk::Fence,
}

impl Fence {
    /// Builds a new fence.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, false)
    }

    /// Builds a new fence already in the "signaled" state.
    #[inline]
    pub fn signaled(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, true)
    }

    fn new_impl(device: &Arc<Device>, signaled: bool) -> Result<Arc<Fence>, OomError> {
        let vk = device.pointers();

        let fence = unsafe {
            let infos = vk::FenceCreateInfo {
                sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO,
                pNext: ptr::null(),
                flags: if signaled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 },
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateFence(device.internal_object(), &infos, ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Fence {
            device: device.clone(),
            fence: fence,
        }))
    }

    /// Returns true if the fence is signaled.
    #[inline]
    pub fn ready(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetFenceStatus(self.device.internal_object(),
                                                             self.fence)));
            match result {
                Success::Success => Ok(true),
                Success::NotReady => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Waits until the fence is signaled, or at least until the number of nanoseconds of the
    /// timeout has elapsed.
    ///
    /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
    pub fn wait(&self, timeout_ns: u64) -> Result<(), OomError> {       // FIXME: wrong error
        unsafe {
            let vk = self.device.pointers();
            let r = try!(check_errors(vk.WaitForFences(self.device.internal_object(), 1,
                                                       &self.fence, vk::TRUE, timeout_ns)));

            match r {
                Success::Success => Ok(()),
                Success::Timeout => panic!(),        // FIXME:
                _ => unreachable!()
            }
        }
    }

    /// Resets the fence.
    #[inline]
    pub fn reset(&self) {
        unsafe {
            let vk = self.device.pointers();
            vk.ResetFences(self.device.internal_object(), 1, &self.fence);
        }
    }

    /// Resets multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panicks if not all fences belong to the same device.
    pub fn multi_reset<'a, I>(iter: I)
        where I: IntoIterator<Item = &'a Fence>
    {
        let mut device = None;

        let fences: Vec<vk::Fence> = iter.into_iter().map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(fence.device.clone()),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to reset multiple fences that didn't belong to the same device"),
            };

            fence.fence
        }).collect();

        if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                vk.ResetFences(device.internal_object(), fences.len() as u32, fences.as_ptr());
            }
        }
    }
}

impl VulkanObject for Fence {
    type Object = vk::Fence;

    #[inline]
    fn internal_object(&self) -> vk::Fence {
        self.fence
    }
}

impl Drop for Fence {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyFence(self.device.internal_object(), self.fence, ptr::null());
        }
    }
}

/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
///
pub struct Semaphore {
    device: Arc<Device>,
    semaphore: vk::Semaphore,
}

impl Semaphore {
    /// Builds a new semaphore.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Semaphore>, OomError> {
        let vk = device.pointers();

        let semaphore = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::SemaphoreCreateInfo = vk::SemaphoreCreateInfo {
                sType: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: 0 as *const _,   // ptr::null()
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSemaphore(device.internal_object(), &INFOS,
                                                 ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Semaphore {
            device: device.clone(),
            semaphore: semaphore,
        }))
    }
}

impl VulkanObject for Semaphore {
    type Object = vk::Semaphore;

    #[inline]
    fn internal_object(&self) -> vk::Semaphore {
        self.semaphore
    }
}

impl Drop for Semaphore {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySemaphore(self.device.internal_object(), self.semaphore, ptr::null());
        }
    }
}

/// Used to block the GPU execution until an event on the CPU occurs.
///
/// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
/// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
/// If the event isn't signaled within these limits, results are undefined and may include
/// device loss.
pub struct Event {
    device: Arc<Device>,
    event: vk::Event,
}

impl Event {
    /// Builds a new event.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Event>, OomError> {
        let vk = device.pointers();

        let event = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::EventCreateInfo = vk::EventCreateInfo {
                sType: vk::STRUCTURE_TYPE_EVENT_CREATE_INFO,
                pNext: 0 as *const _, //ptr::null(),
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateEvent(device.internal_object(), &INFOS,
                                             ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Event {
            device: device.clone(),
            event: event,
        }))
    }

    /// Returns true if the event is signaled.
    #[inline]
    pub fn signaled(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetEventStatus(self.device.internal_object(),
                                                             self.event)));
            match result {
                Success::EventSet => Ok(true),
                Success::EventReset => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Changes the `Event` to the signaled state.
    ///
    /// If a command buffer is waiting on this event, it is then unblocked.
    #[inline]
    pub fn set(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.SetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }

    /// Changes the `Event` to the unsignaled state.
    #[inline]
    pub fn reset(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.ResetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }
}

impl VulkanObject for Event {
    type Object = vk::Event;

    #[inline]
    fn internal_object(&self) -> vk::Event {
        self.event
    }
}

impl Drop for Event {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyEvent(self.device.internal_object(), self.event, ptr::null());
        }
    }
}
<commit_msg>Add some docs<commit_after>//! Synchronization primitives for Vulkan objects.
//!
//! In Vulkan, you have to manually ensure two things:
//!
//! - That a buffer or an image are not read and written simultaneously (similarly to the CPU).
//! - That writes to a buffer or an image are propagated to other queues by inserting memory
//!   barriers.
//!
//! But don't worry ; this is automatically enforced by this library (as long as you don't use
//! any unsafe function). See the `memory` module for more info.
//!
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;

use device::Device;
use device::Queue;
use OomError;
use Success;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Base trait for objects that can be used as resources and must be synchronized.
pub unsafe trait Resource {
    /// Returns in which queue family or families this resource can be used.
    fn sharing_mode(&self) -> &SharingMode;

    /// Returns true if the `gpu_access` function should be passed a fence.
    #[inline]
    fn requires_fence(&self) -> bool {
        true
    }

    /// Returns true if the `gpu_access` function should be passed a semaphore.
    #[inline]
    fn requires_semaphore(&self) -> bool {
        true
    }

    /// Instructs the resource that it is going to be used by the GPU soon in the future. The
    /// function should block if the memory is currently being accessed by the CPU.
    ///
    /// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
    /// be written.
    ///
    /// `queue` is the queue where the command buffer that accesses the memory will be submitted.
    /// If the `gpu_access` function submits something to that queue, it will thus be submitted
    /// beforehand. This behavior can be used for example to submit sparse binding commands.
    ///
    /// `fence` is a fence that will be signaled when this GPU access will stop. It should be
    /// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
    /// returned false, then this value will be `None`.
    ///
    /// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
    /// is intended to be returned later, in a follow-up call to `gpu_access`. If
    /// `requires_semaphore` returned false, then this value will be `None`.
    ///
    /// The function can return a semaphore which will be waited up by the GPU before the
    /// work starts.
    fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
                  semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>;
}

/// Declares in which queue(s) a resource can be used.
///
/// When you create a buffer or an image, you have to tell the Vulkan library in which queue
/// families it will be used. The vulkano library requires you to tell in which queue famiily
/// the resource will be used, even for exclusive mode.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SharingMode {
    /// The resource is used is only one queue family.
    Exclusive(u32),
    /// The resource is used in multiple queue families. Can be slower than `Exclusive`.
    Concurrent(Vec<u32>),       // TODO: Vec is too expensive here
}

impl<'a> From<&'a Arc<Mutex<Queue>>> for SharingMode {
    #[inline]
    fn from(queue: &'a Arc<Mutex<Queue>>) -> SharingMode {
        let queue = queue.lock().unwrap();      // TODO: meh
        SharingMode::Exclusive(queue.family().id())
    }
}

impl<'a> From<&'a [&'a Arc<Mutex<Queue>>]> for SharingMode {
    #[inline]
    fn from(queues: &'a [&'a Arc<Mutex<Queue>>]) -> SharingMode {
        SharingMode::Concurrent(queues.iter().map(|queue| {
            let queue = queue.lock().unwrap();      // TODO: meh
            queue.family().id()
        }).collect())
    }
}

/// A fence is used to know when a command buffer submission has finished its execution.
///
/// When a command buffer accesses a ressource, you have to ensure that the CPU doesn't access
/// the same ressource simultaneously (except for concurrent reads). Therefore in order to know
/// when the CPU can access a ressource again, a fence has to be used.
pub struct Fence {
    device: Arc<Device>,
    fence: vk::Fence,
}

impl Fence {
    /// Builds a new fence.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, false)
    }

    /// Builds a new fence already in the "signaled" state.
    #[inline]
    pub fn signaled(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, true)
    }

    fn new_impl(device: &Arc<Device>, signaled: bool) -> Result<Arc<Fence>, OomError> {
        let vk = device.pointers();

        let fence = unsafe {
            let infos = vk::FenceCreateInfo {
                sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO,
                pNext: ptr::null(),
                flags: if signaled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 },
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateFence(device.internal_object(), &infos, ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Fence {
            device: device.clone(),
            fence: fence,
        }))
    }

    /// Returns true if the fence is signaled.
    #[inline]
    pub fn ready(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetFenceStatus(self.device.internal_object(),
                                                             self.fence)));
            match result {
                Success::Success => Ok(true),
                Success::NotReady => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Waits until the fence is signaled, or at least until the number of nanoseconds of the
    /// timeout has elapsed.
    ///
    /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
    pub fn wait(&self, timeout_ns: u64) -> Result<(), OomError> {       // FIXME: wrong error
        unsafe {
            let vk = self.device.pointers();
            let r = try!(check_errors(vk.WaitForFences(self.device.internal_object(), 1,
                                                       &self.fence, vk::TRUE, timeout_ns)));

            match r {
                Success::Success => Ok(()),
                Success::Timeout => panic!(),        // FIXME:
                _ => unreachable!()
            }
        }
    }

    /// Resets the fence.
    #[inline]
    pub fn reset(&self) {
        unsafe {
            let vk = self.device.pointers();
            vk.ResetFences(self.device.internal_object(), 1, &self.fence);
        }
    }

    /// Resets multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panicks if not all fences belong to the same device.
    pub fn multi_reset<'a, I>(iter: I)
        where I: IntoIterator<Item = &'a Fence>
    {
        let mut device = None;

        let fences: Vec<vk::Fence> = iter.into_iter().map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(fence.device.clone()),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to reset multiple fences that didn't belong to the same device"),
            };

            fence.fence
        }).collect();

        if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                vk.ResetFences(device.internal_object(), fences.len() as u32, fences.as_ptr());
            }
        }
    }
}

impl VulkanObject for Fence {
    type Object = vk::Fence;

    #[inline]
    fn internal_object(&self) -> vk::Fence {
        self.fence
    }
}

impl Drop for Fence {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyFence(self.device.internal_object(), self.fence, ptr::null());
        }
    }
}

/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
pub struct Semaphore {
    device: Arc<Device>,
    semaphore: vk::Semaphore,
}

impl Semaphore {
    /// Builds a new semaphore.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Semaphore>, OomError> {
        let vk = device.pointers();

        let semaphore = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::SemaphoreCreateInfo = vk::SemaphoreCreateInfo {
                sType: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: 0 as *const _,   // ptr::null()
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSemaphore(device.internal_object(), &INFOS,
                                                 ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Semaphore {
            device: device.clone(),
            semaphore: semaphore,
        }))
    }
}

impl VulkanObject for Semaphore {
    type Object = vk::Semaphore;

    #[inline]
    fn internal_object(&self) -> vk::Semaphore {
        self.semaphore
    }
}

impl Drop for Semaphore {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySemaphore(self.device.internal_object(), self.semaphore, ptr::null());
        }
    }
}

/// Used to block the GPU execution until an event on the CPU occurs.
///
/// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
/// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
/// If the event isn't signaled within these limits, results are undefined and may include
/// device loss.
pub struct Event {
    device: Arc<Device>,
    event: vk::Event,
}

impl Event {
    /// Builds a new event.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Event>, OomError> {
        let vk = device.pointers();

        let event = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::EventCreateInfo = vk::EventCreateInfo {
                sType: vk::STRUCTURE_TYPE_EVENT_CREATE_INFO,
                pNext: 0 as *const _, //ptr::null(),
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateEvent(device.internal_object(), &INFOS,
                                             ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Event {
            device: device.clone(),
            event: event,
        }))
    }

    /// Returns true if the event is signaled.
    #[inline]
    pub fn signaled(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetEventStatus(self.device.internal_object(),
                                                             self.event)));
            match result {
                Success::EventSet => Ok(true),
                Success::EventReset => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Changes the `Event` to the signaled state.
    ///
    /// If a command buffer is waiting on this event, it is then unblocked.
    #[inline]
    pub fn set(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.SetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }

    /// Changes the `Event` to the unsignaled state.
    #[inline]
    pub fn reset(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.ResetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }
}

impl VulkanObject for Event {
    type Object = vk::Event;

    #[inline]
    fn internal_object(&self) -> vk::Event {
        self.event
    }
}

impl Drop for Event {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyEvent(self.device.internal_object(), self.event, ptr::null());
        }
    }
}
<|endoftext|>


<commit_before>use crate::*;

use async_std::{net::SocketAddr, prelude::*};

use futures::{
    self,
    sink::SinkExt,
    stream::{self, select, SelectAll, StreamExt},
};
use futures_timer::Delay;

use serde::Serialize;
use std::str::FromStr;
use std::{
    collections::HashMap,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Debug, Serialize)]
struct TripReport {
    index: u64,
    round_trip: u128,
}

pub struct Summary {
    pub mean: Duration,
    pub deviation: Duration,
}

impl FromIterator<Summary> for Summary {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Summary>,
    {
        let (count, mean_sum, deviation_sum) = iter.into_iter().fold(
            (0, Duration::from_secs(0), Duration::from_secs(0)),
            |(mut count, mut mean_sum, mut deviation_sum), result| {
                mean_sum += result.mean;
                deviation_sum += result.deviation;
                count += 1;
                (count, mean_sum, deviation_sum)
            },
        );
        Summary {
            mean: mean_sum / count,
            deviation: deviation_sum / count,
        }
    }
}

impl std::fmt::Debug for Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Summary")
            .field("Mean", &self.mean)
            .field("Deviation", &self.deviation)
            .finish()
    }
}

impl From<Vec<TripReport>> for Summary {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: u128 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as u128;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).pow(2);
        let sum_of_squares: u128 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1);
        let deviation = (variance as f64).sqrt();

        let mean = Duration::from_nanos(mean as u64);
        let deviation = Duration::from_nanos(deviation as u64);

        Summary { mean, deviation }
    }
}

/// Returns a stream that yields `()` `hertz` times per second.
fn ticker(hertz: u32) -> impl Stream<Item = ()> {
    let tick_rate = Duration::from_secs(1) / hertz;
    stream::repeat(0u8).then(move |_| Delay::new(tick_rate))
}

#[derive(Default, Debug)]
struct TransferTracker {
    total_expected: usize,
    live: HashMap<u64, Instant>,
    returned: Vec<TripReport>,
}

impl TransferTracker {
    fn track_send(&mut self, id: u64) {
        self.live.insert(id, Instant::now());
    }

    fn track_return(&mut self, id: u64) {
        if let Some(sent_time) = self.live.remove(&id) {
            self.returned.push(TripReport {
                index: id,
                round_trip: Instant::now().duration_since(sent_time).as_nanos(),
            });
        }
    }

    fn done(&self) -> bool {
        self.returned.len() >= self.total_expected
    }
}

async fn run(
    options: Options,
    client: impl Connection + Unpin,
) -> Result<Summary> {
    enum Input {
        Transfer(TransferCmd),
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);

    let mut tracking = options
        .transfers
        .iter()
        .filter_map(|tx| {
            tx.return_count.map(|total_expected| {
                (
                    tx.stream_id,
                    TransferTracker {
                        total_expected,
                        ..TransferTracker::default()
                    },
                )
            })
        })
        .collect::<HashMap<StreamId, TransferTracker>>();
    let transfers: SelectAll<_> = options
        .transfers
        .into_iter()
        .map(Transfer::stream)
        .collect();

    let mut input_stream =
        select(transfers.map(Input::Transfer), returned_datagrams);

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )?;

                if let Some(tracker) = tracking.get_mut(&stream) {
                    tracker.track_return(benchmark_datagram.id);
                }

                if tracking.values().all(TransferTracker::done) {
                    return Ok(tracking
                        .into_iter()
                        .map(|(_, tracker)| tracker.returned)
                        .map(Summary::from)
                        .collect());
                }
            }
            Input::Transfer(transfer_cmd) => {
                client_sink.send(transfer_cmd.send_cmd).await?;
                if let Some((cumulative_tracking, cmd_tracking)) =
                    transfer_cmd.tracking.and_then(|cmd_tracking| {
                        let cumulative_tracking =
                            tracking.get_mut(&cmd_tracking.stream_id)?;
                        Some((cumulative_tracking, cmd_tracking))
                    })
                {
                    cumulative_tracking.track_send(cmd_tracking.id);
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    /// Periodic transfers, specified in terms of
    /// `stream_id:size:hertz:[return_count]`.
    #[structopt(short = "b", long)]
    pub transfers: Vec<Transfer>,
    #[structopt(subcommand)]
    pub protocol: Protocol,
}

struct TransferCmd {
    send_cmd: SendCmd,
    tracking: Option<TransferMessageTracking>,
}

/// Tracking information for a transfer message on the wire.
struct TransferMessageTracking {
    stream_id: StreamId,
    id: u64,
}

#[derive(Clone, Debug, Copy)]
pub struct Transfer {
    pub stream_id: StreamId,
    pub size: usize,
    pub hertz: u32,
    pub return_count: Option<usize>,
}

impl Transfer {
    fn stream(self) -> impl Stream<Item = TransferCmd> {
        let ticker = ticker(self.hertz);
        let mut id = 0;
        ticker.map(move |_| {
            id += 1;
            match self.return_count {
                Some(_) => TransferCmd {
                    send_cmd: self.send_cmd(id),
                    tracking: Some(TransferMessageTracking {
                        stream_id: self.stream_id,
                        id,
                    }),
                },
                None => TransferCmd {
                    send_cmd: self.send_cmd(ID_DO_NOT_RETURN),
                    tracking: None,
                },
            }
        })
    }

    fn send_cmd(&self, id: u64) -> SendCmd {
        let delivery_mode = DeliveryMode::ReliableOrdered(self.stream_id);
        SendCmd {
            delivery_mode,
            data: bincode::serialize(&BenchmarkDatagram {
                id,
                delivery_mode,
                data: vec![0; self.size],
            })
            .expect("to serialize bulk transfer"),
            ..SendCmd::default()
        }
    }
}

impl FromStr for Transfer {
    type Err = std::num::ParseIntError;
    fn from_str(src: &str) -> std::result::Result<Self, Self::Err> {
        let args: Vec<&str> = src.split(":").collect();

        let stream_id = args[0].parse::<u8>()?;
        let size = args[1].parse::<usize>()?;
        let hertz = args[2].parse::<u32>()?;
        let return_count =
            args.get(3).map(|a| a.parse::<usize>()).transpose()?;

        Ok(Self {
            stream_id: StreamId(stream_id),
            size,
            hertz,
            return_count,
        })
    }
}

pub async fn client_main(options: Options) -> Result<Summary> {
    let address = options.address;
    match options.protocol {
        Protocol::Tcp => {
            run(
                options,
                loop {
                    let result = tcp::TcpConnection::connect(address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(options, enet::EnetConnection::connect(address).await).await
        }
    }
}
<commit_msg>Add stream id to TripReport<commit_after>use crate::*;

use async_std::{net::SocketAddr, prelude::*};

use futures::{
    self,
    sink::SinkExt,
    stream::{self, select, SelectAll, StreamExt},
};
use futures_timer::Delay;

use serde::Serialize;
use std::str::FromStr;
use std::{
    collections::HashMap,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Debug, Serialize)]
struct TripReport {
    stream_id: StreamId,
    index: u64,
    round_trip: u128,
}

pub struct Summary {
    pub mean: Duration,
    pub deviation: Duration,
}

impl FromIterator<Summary> for Summary {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Summary>,
    {
        let (count, mean_sum, deviation_sum) = iter.into_iter().fold(
            (0, Duration::from_secs(0), Duration::from_secs(0)),
            |(mut count, mut mean_sum, mut deviation_sum), result| {
                mean_sum += result.mean;
                deviation_sum += result.deviation;
                count += 1;
                (count, mean_sum, deviation_sum)
            },
        );
        Summary {
            mean: mean_sum / count,
            deviation: deviation_sum / count,
        }
    }
}

impl std::fmt::Debug for Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Summary")
            .field("Mean", &self.mean)
            .field("Deviation", &self.deviation)
            .finish()
    }
}

impl From<Vec<TripReport>> for Summary {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: u128 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as u128;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).pow(2);
        let sum_of_squares: u128 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1);
        let deviation = (variance as f64).sqrt();

        let mean = Duration::from_nanos(mean as u64);
        let deviation = Duration::from_nanos(deviation as u64);

        Summary { mean, deviation }
    }
}

/// Returns a stream that yields `()` `hertz` times per second.
fn ticker(hertz: u32) -> impl Stream<Item = ()> {
    let tick_rate = Duration::from_secs(1) / hertz;
    stream::repeat(0u8).then(move |_| Delay::new(tick_rate))
}

#[derive(Debug)]
struct TransferTracker {
    stream_id: StreamId,
    total_expected: usize,
    live: HashMap<u64, Instant>,
    returned: Vec<TripReport>,
}

impl TransferTracker {
    fn track_send(&mut self, id: u64) {
        self.live.insert(id, Instant::now());
    }

    fn track_return(&mut self, id: u64) {
        if let Some(sent_time) = self.live.remove(&id) {
            self.returned.push(TripReport {
                stream_id: self.stream_id,
                index: id,
                round_trip: Instant::now().duration_since(sent_time).as_nanos(),
            });
        }
    }

    fn done(&self) -> bool {
        self.returned.len() >= self.total_expected
    }
}

async fn run(
    options: Options,
    client: impl Connection + Unpin,
) -> Result<Summary> {
    enum Input {
        Transfer(TransferCmd),
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);

    let mut tracking = options
        .transfers
        .iter()
        .filter_map(|tx| {
            tx.return_count.map(|total_expected| {
                (
                    tx.stream_id,
                    TransferTracker {
                        stream_id: tx.stream_id,
                        total_expected,
                        live: HashMap::new(),
                        returned: vec![]
                    },
                )
            })
        })
        .collect::<HashMap<StreamId, TransferTracker>>();
    let transfers: SelectAll<_> = options
        .transfers
        .into_iter()
        .map(Transfer::stream)
        .collect();

    let mut input_stream =
        select(transfers.map(Input::Transfer), returned_datagrams);

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )?;

                if let Some(tracker) = tracking.get_mut(&stream) {
                    tracker.track_return(benchmark_datagram.id);
                }

                if tracking.values().all(TransferTracker::done) {
                    return Ok(tracking
                        .into_iter()
                        .map(|(_, tracker)| tracker.returned)
                        .map(Summary::from)
                        .collect());
                }
            }
            Input::Transfer(transfer_cmd) => {
                client_sink.send(transfer_cmd.send_cmd).await?;
                if let Some((cumulative_tracking, cmd_tracking)) =
                    transfer_cmd.tracking.and_then(|cmd_tracking| {
                        let cumulative_tracking =
                            tracking.get_mut(&cmd_tracking.stream_id)?;
                        Some((cumulative_tracking, cmd_tracking))
                    })
                {
                    cumulative_tracking.track_send(cmd_tracking.id);
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    /// Periodic transfers, specified in terms of
    /// `stream_id:size:hertz:[return_count]`.
    #[structopt(short = "b", long)]
    pub transfers: Vec<Transfer>,
    #[structopt(subcommand)]
    pub protocol: Protocol,
}

struct TransferCmd {
    send_cmd: SendCmd,
    tracking: Option<TransferMessageTracking>,
}

/// Tracking information for a transfer message on the wire.
struct TransferMessageTracking {
    stream_id: StreamId,
    id: u64,
}

#[derive(Clone, Debug, Copy)]
pub struct Transfer {
    pub stream_id: StreamId,
    pub size: usize,
    pub hertz: u32,
    pub return_count: Option<usize>,
}

impl Transfer {
    fn stream(self) -> impl Stream<Item = TransferCmd> {
        let ticker = ticker(self.hertz);
        let mut id = 0;
        ticker.map(move |_| {
            id += 1;
            match self.return_count {
                Some(_) => TransferCmd {
                    send_cmd: self.send_cmd(id),
                    tracking: Some(TransferMessageTracking {
                        stream_id: self.stream_id,
                        id,
                    }),
                },
                None => TransferCmd {
                    send_cmd: self.send_cmd(ID_DO_NOT_RETURN),
                    tracking: None,
                },
            }
        })
    }

    fn send_cmd(&self, id: u64) -> SendCmd {
        let delivery_mode = DeliveryMode::ReliableOrdered(self.stream_id);
        SendCmd {
            delivery_mode,
            data: bincode::serialize(&BenchmarkDatagram {
                id,
                delivery_mode,
                data: vec![0; self.size],
            })
            .expect("to serialize bulk transfer"),
            ..SendCmd::default()
        }
    }
}

impl FromStr for Transfer {
    type Err = std::num::ParseIntError;
    fn from_str(src: &str) -> std::result::Result<Self, Self::Err> {
        let args: Vec<&str> = src.split(":").collect();

        let stream_id = args[0].parse::<u8>()?;
        let size = args[1].parse::<usize>()?;
        let hertz = args[2].parse::<u32>()?;
        let return_count =
            args.get(3).map(|a| a.parse::<usize>()).transpose()?;

        Ok(Self {
            stream_id: StreamId(stream_id),
            size,
            hertz,
            return_count,
        })
    }
}

pub async fn client_main(options: Options) -> Result<Summary> {
    let address = options.address;
    match options.protocol {
        Protocol::Tcp => {
            run(
                options,
                loop {
                    let result = tcp::TcpConnection::connect(address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(options, enet::EnetConnection::connect(address).await).await
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

//! An RPC library for Rust.
//!
//! Example usage:
//!
//! ```
//! #[macro_use] extern crate tarpc;
//! mod my_server {
//!     service! {
//!         rpc hello(name: String) -> String;
//!         rpc add(x: i32, y: i32) -> i32;
//!     }
//! }
//!
//! use self::my_server::*;
//! use std::time::Duration;
//!
//! struct Server;
//! impl my_server::Service for Server {
//!     fn hello(&self, s: String) -> String {
//!         format!("Hello, {}!", s)
//!     }
//!     fn add(&self, x: i32, y: i32) -> i32 {
//!         x + y
//!     }
//! }
//!
//! fn main() {
//!     let addr = "127.0.0.1:9000";
//!     let serve_handle = Server.spawn(addr).unwrap();
//!     let client = Client::new(serve_handle.dialer()).unwrap();
//!     assert_eq!(3, client.add(1, 2).unwrap());
//!     assert_eq!("Hello, Mom!".to_string(),
//!                client.hello("Mom".to_string()).unwrap());
//!     drop(client);
//!     serve_handle.shutdown();
//! }
//! ```

#![deny(missing_docs)]

extern crate serde;
extern crate bincode;
#[macro_use]
extern crate log;
extern crate scoped_pool;
extern crate unix_socket;

macro_rules! pos {
    () => (concat!(file!(), ":", line!()))
}

/// Provides the tarpc client and server, which implements the tarpc protocol.
/// The protocol is defined by the implementation.
pub mod protocol;

/// Provides the macro used for constructing rpc services and client stubs.
pub mod macros;

/// Provides transport traits and implementations.
pub mod transport;

pub use protocol::{Config, Error, Result, ServeHandle};
<commit_msg>Simplify lib.rs example<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

//! An RPC library for Rust.
//!
//! Example usage:
//!
//! ```
//! #[macro_use] extern crate tarpc;
//! mod my_server {
//!     service! {
//!         rpc hello(name: String) -> String;
//!         rpc add(x: i32, y: i32) -> i32;
//!     }
//! }
//!
//! use self::my_server::*;
//! use std::time::Duration;
//!
//! struct Server;
//! impl my_server::Service for Server {
//!     fn hello(&self, s: String) -> String {
//!         format!("Hello, {}!", s)
//!     }
//!     fn add(&self, x: i32, y: i32) -> i32 {
//!         x + y
//!     }
//! }
//!
//! fn main() {
//!     let serve_handle = Server.spawn("localhost:0").unwrap();
//!     let client = Client::new(serve_handle.dialer()).unwrap();
//!     assert_eq!(3, client.add(1, 2).unwrap());
//!     assert_eq!("Hello, Mom!".to_string(),
//!                client.hello("Mom".to_string()).unwrap());
//!     drop(client);
//!     serve_handle.shutdown();
//! }
//! ```

#![deny(missing_docs)]

extern crate serde;
extern crate bincode;
#[macro_use]
extern crate log;
extern crate scoped_pool;
extern crate unix_socket;

macro_rules! pos {
    () => (concat!(file!(), ":", line!()))
}

/// Provides the tarpc client and server, which implements the tarpc protocol.
/// The protocol is defined by the implementation.
pub mod protocol;

/// Provides the macro used for constructing rpc services and client stubs.
pub mod macros;

/// Provides transport traits and implementations.
pub mod transport;

pub use protocol::{Config, Error, Result, ServeHandle};
<|endoftext|>


<commit_before>use std::sync::Mutex;
use std::thread;
use time;

use common::block_position::BlockPosition;
use common::communicate::{ClientToServer, ServerToClient, TerrainBlockSend};
use common::interval_timer::IntervalTimer;
use common::surroundings_loader::LODChange;

use client::Client;
use load_terrain::{load_terrain_block, lod_index};
use server_update::apply_server_update;
use view_update::ClientToView;

pub fn update_thread<RecvServer, RecvBlock, UpdateView, UpdateServer, QueueBlock>(
  quit: &Mutex<bool>,
  client: &Client,
  recv_server: &mut RecvServer,
  recv_block: &mut RecvBlock,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
  queue_block: &mut QueueBlock,
) where
  RecvServer: FnMut() -> Option<ServerToClient>,
  RecvBlock: FnMut() -> Option<TerrainBlockSend>,
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(ClientToServer),
  QueueBlock: FnMut(TerrainBlockSend),
{
  let mut surroundings_timer = IntervalTimer::new(500_000_000, time::precise_time_ns());

  'update_loop: loop {
    if *quit.lock().unwrap() == true {
      break 'update_loop;
    } else if let Some(up) = recv_server() {
      apply_server_update(
        client,
        update_view,
        update_server,
        queue_block,
        up,
      );
    } else {
      if surroundings_timer.update(time::precise_time_ns()) > 0 {
        let position = *client.player_position.lock().unwrap();
        let position = BlockPosition::from_world_position(&position);
        let mut cap = range(0, 1 << 16);
        client.surroundings_loader.lock().unwrap().update(
          position,
          || { cap.next().is_some() },
          |lod_change| {
            match lod_change {
              LODChange::Load(block_position, distance) => {
                let lod = lod_index(distance);
                update_server(ClientToServer::RequestBlock(client.id, block_position, lod));
              },
              LODChange::Unload(block_position) => {
                // The block removal code is duplicated elsewhere.

                client.loaded_blocks
                  .lock().unwrap()
                  .remove(&block_position)
                  // If it wasn't loaded, don't unload anything.
                  .map(|(block, prev_lod)| {
                    for id in block.ids.iter() {
                      update_view(ClientToView::RemoveTerrain(*id));
                    }

                    update_view(ClientToView::RemoveBlockData(block_position, prev_lod));
                  });
              },
            };
          },
        );
      } else if let Some(block) = recv_block() {
        load_terrain_block(
          client,
          update_view,
          block,
        );
      } else {
        thread::yield_now();
      }
    }
  }
}
<commit_msg>Client doesn't re-request properly-loaded blocks.<commit_after>use std::sync::Mutex;
use std::thread;
use time;

use common::block_position::BlockPosition;
use common::communicate::{ClientToServer, ServerToClient, TerrainBlockSend};
use common::interval_timer::IntervalTimer;
use common::surroundings_loader::LODChange;

use client::Client;
use load_terrain::{load_terrain_block, lod_index};
use server_update::apply_server_update;
use view_update::ClientToView;

pub fn update_thread<RecvServer, RecvBlock, UpdateView, UpdateServer, QueueBlock>(
  quit: &Mutex<bool>,
  client: &Client,
  recv_server: &mut RecvServer,
  recv_block: &mut RecvBlock,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
  queue_block: &mut QueueBlock,
) where
  RecvServer: FnMut() -> Option<ServerToClient>,
  RecvBlock: FnMut() -> Option<TerrainBlockSend>,
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(ClientToServer),
  QueueBlock: FnMut(TerrainBlockSend),
{
  let mut surroundings_timer = IntervalTimer::new(500_000_000, time::precise_time_ns());

  'update_loop: loop {
    if *quit.lock().unwrap() == true {
      break 'update_loop;
    } else if let Some(up) = recv_server() {
      apply_server_update(
        client,
        update_view,
        update_server,
        queue_block,
        up,
      );
    } else {
      if surroundings_timer.update(time::precise_time_ns()) > 0 {
        let position = *client.player_position.lock().unwrap();
        let position = BlockPosition::from_world_position(&position);
        let mut cap = range(0, 1 << 16);
        client.surroundings_loader.lock().unwrap().update(
          position,
          || { cap.next().is_some() },
          |lod_change| {
            match lod_change {
              LODChange::Load(block_position, distance) => {
                let lod = lod_index(distance);
                let loaded_lod =
                  client.loaded_blocks
                  .lock().unwrap()
                  .get(&block_position)
                  .map(|&(_, lod)| lod);
                if loaded_lod != Some(lod) {
                  update_server(ClientToServer::RequestBlock(client.id, block_position, lod));
                } else {
                  trace!("Not re-loading {:?} at {:?}", block_position, lod);
                }
              },
              LODChange::Unload(block_position) => {
                // The block removal code is duplicated elsewhere.

                client.loaded_blocks
                  .lock().unwrap()
                  .remove(&block_position)
                  // If it wasn't loaded, don't unload anything.
                  .map(|(block, prev_lod)| {
                    for id in block.ids.iter() {
                      update_view(ClientToView::RemoveTerrain(*id));
                    }

                    update_view(ClientToView::RemoveBlockData(block_position, prev_lod));
                  });
              },
            };
          },
        );
      } else if let Some(block) = recv_block() {
        trace!("Got block: {:?} at {:?}", block.position, block.lod);
        load_terrain_block(
          client,
          update_view,
          block,
        );
      } else {
        thread::yield_now();
      }
    }
  }
}
<|endoftext|>


<commit_before>use glium::backend::Facade;
use std::rc::Rc;
use glium::{self, DrawParameters, IndexBuffer, Program, VertexBuffer};
use glium::index::PrimitiveType;
use GameContext;
use Camera;
use glium::draw_parameters::{BackfaceCullingMode, DepthTest};
use util::ToArr;
use base::math::*;

pub struct SkyView {
    vertex_buffer: VertexBuffer<Vertex>,
    index_buffer: IndexBuffer<u32>,
    program: Program,
    context: Rc<GameContext>,
}

impl SkyView {
    pub fn new(context: Rc<GameContext>) -> Self {

        const SKYDOME_SIZE: f32 = 1000.0;
        let raw_vertex_buffer = vec![
            Vertex { position: [0.0, -SKYDOME_SIZE, 0.0], color: [0.7, 0.0, 0.0]},
            Vertex { position: [SKYDOME_SIZE, 0.0, 0.0], color: [0.5, 0.2, 0.0]},
            Vertex { position: [0.0, SKYDOME_SIZE, 0.0], color: [0.0, 0.0, 0.7]},
            Vertex { position: [-SKYDOME_SIZE, 0.0, 0.0], color: [0.0, 0.0, 0.7]},
            Vertex { position: [0.0, 0.0, -SKYDOME_SIZE], color: [0.0, 0.0, 1.0]},
            Vertex { position: [0.0, 0.0, SKYDOME_SIZE], color: [0.0, 0.0, 1.0]},
        ];

        //         let raw_vertex_buffer = vec![
        //     Vertex { position: [0.0, -60.0, 60.0], color: [1.0, 0.0, 0.0]},
        //     Vertex { position: [60.0, 0.0, 60.0], color: [0.0, 1.0, 0.0]},
        //     Vertex { position: [0.0, 60.0, 60.0], color: [0.0, 0.0, 1.0]},
        //     Vertex { position: [-60.0, 0.0, 60.0], color: [0.0, 0.0, 1.0]},
        //     Vertex { position: [0.0, 0.0, 0.0], color: [0.0, 0.0, 1.0]},
        //     Vertex { position: [0.0, 0.0, 120.0], color: [0.0, 0.0, 1.0]},
        // ];

        let vbuf = VertexBuffer::new(context.get_facade(), &raw_vertex_buffer).unwrap();

        // Indices
        let raw_index_buffer = [0, 1, 4, 1, 2, 4, 2,3,4,3,0,4,1,0,5,0,3,5,3,2,5,2,1,5]; //TrianglesList
        // let raw_index_buffer = [0, 1, 4, 2, -1, 2, 4, 3, 0, -1, 3, 2, 5, 1, -1, 3, 5, 0, 1]; // would need primitive restart
        let ibuf = IndexBuffer::new(context.get_facade(),
                                    PrimitiveType::TrianglesList,
                                    &raw_index_buffer)
            .unwrap();

        let prog = Program::from_source(context.get_facade(),
                                        include_str!("skydome.vert"),
                                        include_str!("skydome.frag"),
                                        None)
            .unwrap();

        SkyView {
            vertex_buffer: vbuf,
            index_buffer: ibuf,
            program: prog,
            context: context,
        }
    }

    pub fn draw_skydome<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {

        let pos = Point3::new(0.0, 0.0, 0.0);
        let mut view_matrix =
            Matrix4::look_at(pos, pos + camera.get_look_at_vector(), Vector3::unit_z());

        let uniforms = uniform! {
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: view_matrix.to_arr(),
        };
        let params = DrawParameters {
            depth: glium::Depth {
                write: false,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            ..Default::default()
        };

        surface.draw(&self.vertex_buffer,
                  &self.index_buffer,
                  &self.program,
                  &uniforms,
                  &params)
            .unwrap();
    }
}

/// Vertex type used to render chunks (or hex pillars).
#[derive(Debug, Copy, Clone)]
struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 3],
}

implement_vertex!(Vertex, position, color);
<commit_msg>remove comment<commit_after>use glium::backend::Facade;
use std::rc::Rc;
use glium::{self, DrawParameters, IndexBuffer, Program, VertexBuffer};
use glium::index::PrimitiveType;
use GameContext;
use Camera;
use glium::draw_parameters::{BackfaceCullingMode, DepthTest};
use util::ToArr;
use base::math::*;

pub struct SkyView {
    vertex_buffer: VertexBuffer<Vertex>,
    index_buffer: IndexBuffer<u32>,
    program: Program,
    context: Rc<GameContext>,
}

impl SkyView {
    pub fn new(context: Rc<GameContext>) -> Self {

        const SKYDOME_SIZE: f32 = 1000.0;
        let raw_vertex_buffer = vec![
            Vertex { position: [0.0, -SKYDOME_SIZE, 0.0], color: [0.7, 0.0, 0.0]},
            Vertex { position: [SKYDOME_SIZE, 0.0, 0.0], color: [0.5, 0.2, 0.0]},
            Vertex { position: [0.0, SKYDOME_SIZE, 0.0], color: [0.0, 0.0, 0.7]},
            Vertex { position: [-SKYDOME_SIZE, 0.0, 0.0], color: [0.0, 0.0, 0.7]},
            Vertex { position: [0.0, 0.0, -SKYDOME_SIZE], color: [0.0, 0.0, 1.0]},
            Vertex { position: [0.0, 0.0, SKYDOME_SIZE], color: [0.0, 0.0, 1.0]},
        ];

        let vbuf = VertexBuffer::new(context.get_facade(), &raw_vertex_buffer).unwrap();

        // Indices
        let raw_index_buffer = [0, 1, 4, 1, 2, 4, 2,3,4,3,0,4,1,0,5,0,3,5,3,2,5,2,1,5]; //TrianglesList
        // let raw_index_buffer = [0, 1, 4, 2, -1, 2, 4, 3, 0, -1, 3, 2, 5, 1, -1, 3, 5, 0, 1]; // would need primitive restart
        let ibuf = IndexBuffer::new(context.get_facade(),
                                    PrimitiveType::TrianglesList,
                                    &raw_index_buffer)
            .unwrap();

        let prog = Program::from_source(context.get_facade(),
                                        include_str!("skydome.vert"),
                                        include_str!("skydome.frag"),
                                        None)
            .unwrap();

        SkyView {
            vertex_buffer: vbuf,
            index_buffer: ibuf,
            program: prog,
            context: context,
        }
    }

    pub fn draw_skydome<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {

        let pos = Point3::new(0.0, 0.0, 0.0);
        let mut view_matrix =
            Matrix4::look_at(pos, pos + camera.get_look_at_vector(), Vector3::unit_z());

        let uniforms = uniform! {
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: view_matrix.to_arr(),
        };
        let params = DrawParameters {
            depth: glium::Depth {
                write: false,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            ..Default::default()
        };

        surface.draw(&self.vertex_buffer,
                  &self.index_buffer,
                  &self.program,
                  &uniforms,
                  &params)
            .unwrap();
    }
}

/// Vertex type used to render chunks (or hex pillars).
#[derive(Debug, Copy, Clone)]
struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 3],
}

implement_vertex!(Vertex, position, color);
<|endoftext|>


<commit_before>extern crate httpd = "tiny-http";

use std::io::timer;

#[allow(dead_code)]
mod support;

#[test]
fn connection_close() {
    let mut client = support::new_client_to_hello_world_server(2);

    (write!(client, "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n")).unwrap();
    timer::sleep(1000);

    (write!(client, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn http_1_0_connection_close() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn poor_network_test() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "G")).unwrap();
    timer::sleep(100);
    (write!(client, "ET /he")).unwrap();
    timer::sleep(100);
    (write!(client, "llo HT")).unwrap();
    timer::sleep(100);
    (write!(client, "TP/1.")).unwrap();
    timer::sleep(100);
    (write!(client, "1\r\nHo")).unwrap();
    timer::sleep(100);
    (write!(client, "st: localho")).unwrap();
    timer::sleep(100);
    (write!(client, "st\r\nConnec")).unwrap();
    timer::sleep(100);
    (write!(client, "tion: close\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert!(data.as_slice().ends_with("hello world"));
}

#[test]
fn pipelining_test() {
    let mut client = support::new_client_to_hello_world_server(3);

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /hello HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /world HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert_eq!(data.as_slice().split_str("hello world").count(), 4);
}
<commit_msg>Add failing test about failed requests<commit_after>extern crate httpd = "tiny-http";

use std::io::timer;

#[allow(dead_code)]
mod support;

#[test]
fn connection_close() {
    let mut client = support::new_client_to_hello_world_server(2);

    (write!(client, "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n")).unwrap();
    timer::sleep(1000);

    (write!(client, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn http_1_0_connection_close() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn poor_network_test() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "G")).unwrap();
    timer::sleep(100);
    (write!(client, "ET /he")).unwrap();
    timer::sleep(100);
    (write!(client, "llo HT")).unwrap();
    timer::sleep(100);
    (write!(client, "TP/1.")).unwrap();
    timer::sleep(100);
    (write!(client, "1\r\nHo")).unwrap();
    timer::sleep(100);
    (write!(client, "st: localho")).unwrap();
    timer::sleep(100);
    (write!(client, "st\r\nConnec")).unwrap();
    timer::sleep(100);
    (write!(client, "tion: close\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert!(data.as_slice().ends_with("hello world"));
}

#[test]
fn pipelining_test() {
    let mut client = support::new_client_to_hello_world_server(3);

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /hello HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /world HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert_eq!(data.as_slice().split_str("hello world").count(), 4);
}

#[test]
#[ignore]   // TODO: fails
fn server_crash_results_in_response() {
    use std::io::net::tcp::TcpStream;

    let (server, port) = httpd::Server::new_with_random_port().unwrap();
    let mut client = TcpStream::connect("127.0.0.1", port).unwrap();

    spawn(proc() {
        server.recv().unwrap();
        // oops, server crash
    });

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let content = client.read_to_string().unwrap();
    assert!(content.as_slice().slice_from(9).starts_with("5"));   // 5xx status code
}
<|endoftext|>