<commit_before>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x3F000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file= OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut u32,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<commit_msg>use MapOption::Offset instead of MapOption::Addr<commit_after>//volatile_store is the same as `*ptr = value;` (except that the optimiser won't touch it)
#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: usize = 0x3F000000;
const GPIO_BASE: usize = BCM2708_PERI_BASE + 0x200000;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = 4 * 1024;

pub struct Bcm2835Peripheral {
    pub addr_p: *const usize,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut usize
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = &[
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            MapOption::MapOffset(GPIO_BASE),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };

        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut usize,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: usize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: usize) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: usize) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<|endoftext|>


<commit_before>
const MEMORY_SIZE: usize = 1024 * 1024;

type Register = (usize, &'static str);

trait RegisterHelpers {
    fn addr(&self) -> usize;
    fn name(&self) -> &'static str;
}

impl RegisterHelpers for Register {
    fn addr(&self) -> usize {
        self.0
    }

    fn name(&self) -> &'static str {
        self.1
    }
}

const EAX: Register = (0, "EAX");
const ECX: Register = (1, "ECX");
const EDX: Register = (2, "EDX");
const EBX: Register = (3, "EBX");
const ESP: Register = (4, "ESP");
const EBP: Register = (5, "EBP");
const ESI: Register = (6, "ESI");
const EDI: Register = (7, "EDI");
const REGISTERS: [Register; 8] = [EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI];

struct Emulator {
    registers: [u32; REGISTERS.len()],
    eflags: u32,
    memory: Vec<u8>,
    eip: u32,
}

impl Emulator {
    fn create(size: usize, eip: u32, esp: u32) -> Emulator {
        let mut regs = [0; REGISTERS.len()];
        regs[ESP.addr()] = esp;
        Emulator {
            registers: regs,
            memory: Vec::with_capacity(size),
            eflags: 0,
            eip: eip,
        }
    }

    fn dump_registers(&self) {
        for i in REGISTERS.iter() {
            println!("{} = {}", i.name(), self.registers[i.addr()]);
        }

        println!("EIP = {}", self.eip);
    }

    fn get_code8(&self, index: usize) -> u32 {
        self.memory[self.eip as usize + index] as u32
    }

    fn get_sign_code8(&self, index: usize) -> i32 {
        self.memory[self.eip as usize + index] as i32
    }

    fn get_code32(&self, index: usize) -> u32 {
        let mut ret: u32 = 0;
        for i in 0..4 {
            ret |= self.get_code8(index + i) << (i * 8)
        }
        return ret;
    }

    fn mov_r32_imm32(&self) {
    }

    fn short_jump(&self) {
    }
}

fn main() {
    println!("hello");
}
<commit_msg>Update vm.<commit_after>use std::env;
use std::fs::File;
use std::io::Read;

const MEMORY_SIZE: usize = 1024 * 1024;

type Register = (usize, &'static str);

trait RegisterHelpers {
    fn addr(&self) -> usize;
    fn name(&self) -> &'static str;
}

impl RegisterHelpers for Register {
    fn addr(&self) -> usize {
        self.0
    }

    fn name(&self) -> &'static str {
        self.1
    }
}

const EAX: Register = (0, "EAX");
const ECX: Register = (1, "ECX");
const EDX: Register = (2, "EDX");
const EBX: Register = (3, "EBX");
const ESP: Register = (4, "ESP");
const EBP: Register = (5, "EBP");
const ESI: Register = (6, "ESI");
const EDI: Register = (7, "EDI");
const REGISTERS: [Register; 8] = [EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI];

struct Emulator {
    registers: [u32; REGISTERS.len()],
    eflags: u32,
    memory: Vec<u8>,
    eip: u32,
}

impl Emulator {
    fn create(size: usize, eip: u32, esp: u32) -> Emulator {
        let mut regs = [0; REGISTERS.len()];
        regs[ESP.addr()] = esp;
        Emulator {
            registers: regs,
            memory: Vec::with_capacity(size),
            eflags: 0,
            eip: eip,
        }
    }

    fn dump_registers(&self) {
        for i in REGISTERS.iter() {
            println!("{} = {}", i.name(), self.registers[i.addr()]);
        }

        println!("EIP = {}", self.eip);
    }

    fn get_code8(&self, index: usize) -> u32 {
        self.memory[self.eip as usize + index] as u32
    }

    fn get_sign_code8(&self, index: usize) -> i32 {
        self.memory[self.eip as usize + index] as i32
    }

    fn get_code32(&self, index: usize) -> u32 {
        let mut ret: u32 = 0;
        for i in 0..4 {
            ret |= self.get_code8(index + i) << (i * 8)
        }
        return ret;
    }

    fn mov_r32_imm32(&self) {
    }

    fn short_jump(&self) {
    }
}

fn main() {

    let args: Vec<String> = env::args().collect();
    let mut buffer = String::new();

    if args.len() != 2 {
        println!("usage: vm filename");
        return;
    }

    let filename: & String = & args[1];

    match File::open(filename) {
        Ok(mut file) => match file.read_to_string(&mut buffer) {
            Ok(_) => {}
            Err(e) => {
                panic!(e);
            }
        },
        Err(e) => {
            panic!(e);
        }
    };
    println!("hello {:?}", buffer);
}
<|endoftext|>


<commit_before>//! [GET /_matrix/media/r0/thumbnail/{serverName}/{mediaId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-thumbnail-servername-mediaid)

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::ServerName;
use serde::{Deserialize, Serialize};

/// The desired resizing method.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Method {
    /// Crop the original to produce the requested image dimensions.
    Crop,

    /// Maintain the original aspect ratio of the source image.
    Scale,
}

ruma_api! {
    metadata: {
        description: "Get a thumbnail of content from the media store.",
        method: GET,
        name: "get_content_thumbnail",
        path: "/_matrix/media/r0/thumbnail/:server_name/:media_id",
        rate_limited: true,
        authentication: None,
    }

    request: {
        /// The media ID from the mxc:// URI (the path component).
        #[ruma_api(path)]
        pub media_id: &'a str,

        /// The server name from the mxc:// URI (the authoritory component).
        #[ruma_api(path)]
        pub server_name: &'a ServerName,

        /// The desired resizing method.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub method: Option<Method>,

        /// The *desired* width of the thumbnail. The actual thumbnail may not match the size
        /// specified.
        #[ruma_api(query)]
        pub width: UInt,

        /// The *desired* height of the thumbnail. The actual thumbnail may not match the size
        /// specified.
        #[ruma_api(query)]
        pub height: UInt,

        /// Whether to fetch media deemed remote.
        ///
        /// Used to prevent routing loops. Defaults to `true`.
        #[ruma_api(query)]
        #[serde(default = "ruma_serde::default_true", skip_serializing_if = "ruma_serde::is_true")]
        pub allow_remote: bool,
    }

    response: {
        /// A thumbnail of the requested content.
        #[ruma_api(raw_body)]
        pub file: Vec<u8>,

        /// The content type of the thumbnail.
        #[ruma_api(header = CONTENT_TYPE)]
        pub content_type: Option<String>,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given media ID, server name, desired thumbnail width and
    /// desired thumbnail height.
    pub fn new(media_id: &'a str, server_name: &'a ServerName, width: UInt, height: UInt) -> Self {
        Self { media_id, server_name, method: None, width, height, allow_remote: true }
    }
}

impl Response {
    /// Creates a new `Response` with the given thumbnail.
    pub fn new(file: Vec<u8>) -> Self {
        Self { file, content_type: None }
    }
}
<commit_msg>client-api: Allow custom values for get_content_thumbnail::Method<commit_after>//! [GET /_matrix/media/r0/thumbnail/{serverName}/{mediaId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-thumbnail-servername-mediaid)

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::ServerName;
use ruma_serde::StringEnum;

/// The desired resizing method.
#[derive(Clone, Debug, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum Method {
    /// Crop the original to produce the requested image dimensions.
    Crop,

    /// Maintain the original aspect ratio of the source image.
    Scale,

    #[doc(hidden)]
    _Custom(String),
}

ruma_api! {
    metadata: {
        description: "Get a thumbnail of content from the media store.",
        method: GET,
        name: "get_content_thumbnail",
        path: "/_matrix/media/r0/thumbnail/:server_name/:media_id",
        rate_limited: true,
        authentication: None,
    }

    request: {
        /// The media ID from the mxc:// URI (the path component).
        #[ruma_api(path)]
        pub media_id: &'a str,

        /// The server name from the mxc:// URI (the authoritory component).
        #[ruma_api(path)]
        pub server_name: &'a ServerName,

        /// The desired resizing method.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub method: Option<Method>,

        /// The *desired* width of the thumbnail. The actual thumbnail may not match the size
        /// specified.
        #[ruma_api(query)]
        pub width: UInt,

        /// The *desired* height of the thumbnail. The actual thumbnail may not match the size
        /// specified.
        #[ruma_api(query)]
        pub height: UInt,

        /// Whether to fetch media deemed remote.
        ///
        /// Used to prevent routing loops. Defaults to `true`.
        #[ruma_api(query)]
        #[serde(default = "ruma_serde::default_true", skip_serializing_if = "ruma_serde::is_true")]
        pub allow_remote: bool,
    }

    response: {
        /// A thumbnail of the requested content.
        #[ruma_api(raw_body)]
        pub file: Vec<u8>,

        /// The content type of the thumbnail.
        #[ruma_api(header = CONTENT_TYPE)]
        pub content_type: Option<String>,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given media ID, server name, desired thumbnail width and
    /// desired thumbnail height.
    pub fn new(media_id: &'a str, server_name: &'a ServerName, width: UInt, height: UInt) -> Self {
        Self { media_id, server_name, method: None, width, height, allow_remote: true }
    }
}

impl Response {
    /// Creates a new `Response` with the given thumbnail.
    pub fn new(file: Vec<u8>) -> Self {
        Self { file, content_type: None }
    }
}
<|endoftext|>


<commit_before>extern crate vcpkg;
extern crate clap;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {

    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(Arg::with_name("target")
            .short("t")
            .long("target")
            .value_name("TARGET TRIPLE")
            .help("the rust toolchain triple to find libraries for")
            .takes_value(true)
            .default_value("x86_64-pc-windows-msvc"))
        .subcommand(SubCommand::with_name("probe")
            .about("try to find a library")
            .arg(Arg::with_name("library")
                .index(1)
                .required(true)
                .help("probe for a library and display paths and cargo metadata"))
            .arg(Arg::with_name("linkage")
                .short("l")
                .long("linkage")
                .takes_value(true)
                .possible_values(&["dll", "static"])));

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {

        let lib_name = matches.value_of("library").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    // do nothing
                }
                &"static" => {
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.probe(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("\t{}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("\t{}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("\t{}", line.display());
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);

            }
        }
    }
}<commit_msg>set +crt-static<commit_after>extern crate vcpkg;
extern crate clap;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {

    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(Arg::with_name("target")
            .short("t")
            .long("target")
            .value_name("TARGET TRIPLE")
            .help("the rust toolchain triple to find libraries for")
            .takes_value(true)
            .default_value("x86_64-pc-windows-msvc"))
        .subcommand(SubCommand::with_name("probe")
            .about("try to find a library")
            .arg(Arg::with_name("library")
                .index(1)
                .required(true)
                .help("probe for a library and display paths and cargo metadata"))
            .arg(Arg::with_name("linkage")
                .short("l")
                .long("linkage")
                .takes_value(true)
                .possible_values(&["dll", "static"])));

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {

        let lib_name = matches.value_of("library").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    // do nothing
                }
                &"static" => {
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "+crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.probe(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("\t{}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("\t{}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("\t{}", line.display());
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);

            }
        }
    }
}<|endoftext|>


<commit_before>use registry::{Enum, Registry, Cmd, Ns};
use std::old_io::IoResult;

mod ty;
pub mod global_gen;
pub mod static_gen;
pub mod struct_gen;
pub mod static_struct_gen;

/// Trait for a bindings generator.
pub trait Generator {
    /// Builds the GL bindings.
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> IoResult<()> where W: Writer;
}

/// This function generates a `const name: type = value;` item.
fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> IoResult<()> where W: Writer {
    // computing the name of the enum
    // if the original starts with a digit, adding an underscore prefix.
    let ident = if (enm.ident.as_slice().char_at(0)).is_numeric() {
        format!("_{}", enm.ident)
    } else {
        enm.ident.clone()
    };

    // if the enum has the value of the form `((Type)Value)`, then `val_regexed` contains `(Type, Value)`
    let val_regexed = {
        if enm.value.starts_with("((") && enm.value.ends_with(")") {
            let separator = enm.value.as_slice().chars().skip(2).position(|c| c == ')').unwrap();
            Some((enm.value.slice(2, separator + 2), enm.value.slice_from(separator + 3).as_slice().trim_matches(')')))
        } else {
            None
        }
    };

    // computing the type of the enum
    let ty = {
        // some enums have a value of the form `((Type)Value)` ; if this is the case, we need to
        //  replace the type of the enum (which is GLenum by default) by the type in the expression
        if let Some((ty, _)) = val_regexed {
            // if the value is like `((Type)Value)`, then the type is `types::Type`
            format!("{}{}", types_prefix, ty)

        } else if enm.value.as_slice().starts_with("\"") {
            // some values are of the form "Value" ; if this is the case, we use `&'static str`
            //  instead of `GLenum`
            "&'static str".to_string()

        } else {
            // some values are `TRUE` or `FALSE`, in which case we use `GLboolean` instead of
            //  `GLenum`
            match ident.as_slice() {
                "TRUE" | "FALSE" => format!("{}GLboolean", types_prefix),
                _ => match enm.ty {
                    Some(ref s) if s.as_slice() == "ull" => format!("{}GLuint64", types_prefix),
                    _ => format!("{}GLenum", types_prefix)
                }
            }
        }
    };

    // computing the value of the enum
    let value = {
        // similar to the type, some values are `((Type)Value)`
        // replacing "((Type)Value)" by "Value as types::Type"
        if let Some((ty, val)) = val_regexed {
            format!("{} as {}{}", val, types_prefix, ty)
        } else {
            enm.value.clone()
        }
    };

    writeln!(dest, "
        #[stable]
        #[allow(dead_code)]
        #[allow(non_upper_case_globals)]
        pub const {}: {} = {};
    ", ident, ty, value)
}

/// Generates all the type aliases for a namespace.
///
/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
///  things that we can't obtain from the XML files.
pub fn gen_type_aliases<W>(namespace: &Ns, dest: &mut W) -> IoResult<()> where W: Writer {
    match *namespace {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => {
            try!(ty::build_gl_aliases(dest));
        }

        Ns::Glx => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_x_aliases(dest));
            try!(ty::build_glx_aliases(dest));
        }

        Ns::Wgl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_win_aliases(dest));
            try!(ty::build_wgl_aliases(dest));
        }

        Ns::Egl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_egl_aliases(dest));
        }
    }

    Ok(())
}

/// Generates the list of Rust `Arg`s that a `Cmd` requires.
pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
    cmd.params.iter()
        .map(|binding| {
            // variable name of the binding
            let ident = match binding.ident.as_slice() {
                "in" => "in_",
                "ref" => "ref_",
                "type" => "type_",
                ident => ident,
            };

            // rust type of the binding
            let ty = ty::to_rust_ty(binding.ty.as_slice());

            // returning
            if with_idents && with_types {
                format!("{}: {}", ident, ty)
            } else if with_types {
                format!("{}", ty)
            } else if with_idents {
                format!("{}", ident)
            } else {
                panic!()
            }
        })
        .collect()
}

/// Generates the Rust return type of a `Cmd`.
pub fn gen_return_type(cmd: &Cmd) -> String {
    // turn the return type into a Rust type
    let ty = ty::to_rust_ty(cmd.proto.ty.as_slice());

    // ... but there is one more step: if the Rust type is `c_void`, we replace it with `()`
    if ty == "__gl_imports::libc::c_void" {
        return "()".to_string();
    }

    ty.to_string()
}

/// Generates the native symbol name of a `Cmd`.
///
/// Example results: `"glClear"`, `"wglCreateContext"`, etc.
pub fn gen_symbol_name(ns: &Ns, cmd: &str) -> String {
    (match *ns {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => "gl",
        Ns::Glx => "glX",
        Ns::Wgl => "wgl",
        Ns::Egl => "egl",
    }).to_string() + cmd
}
<commit_msg>Fix some excess spacing in generated file.<commit_after>use registry::{Enum, Registry, Cmd, Ns};
use std::old_io::IoResult;

mod ty;
pub mod global_gen;
pub mod static_gen;
pub mod struct_gen;
pub mod static_struct_gen;

/// Trait for a bindings generator.
pub trait Generator {
    /// Builds the GL bindings.
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> IoResult<()> where W: Writer;
}

/// This function generates a `const name: type = value;` item.
fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> IoResult<()> where W: Writer {
    // computing the name of the enum
    // if the original starts with a digit, adding an underscore prefix.
    let ident = if (enm.ident.as_slice().char_at(0)).is_numeric() {
        format!("_{}", enm.ident)
    } else {
        enm.ident.clone()
    };

    // if the enum has the value of the form `((Type)Value)`, then `val_regexed` contains `(Type, Value)`
    let val_regexed = {
        if enm.value.starts_with("((") && enm.value.ends_with(")") {
            let separator = enm.value.as_slice().chars().skip(2).position(|c| c == ')').unwrap();
            Some((enm.value.slice(2, separator + 2), enm.value.slice_from(separator + 3).as_slice().trim_matches(')')))
        } else {
            None
        }
    };

    // computing the type of the enum
    let ty = {
        // some enums have a value of the form `((Type)Value)` ; if this is the case, we need to
        //  replace the type of the enum (which is GLenum by default) by the type in the expression
        if let Some((ty, _)) = val_regexed {
            // if the value is like `((Type)Value)`, then the type is `types::Type`
            format!("{}{}", types_prefix, ty)

        } else if enm.value.as_slice().starts_with("\"") {
            // some values are of the form "Value" ; if this is the case, we use `&'static str`
            //  instead of `GLenum`
            "&'static str".to_string()

        } else {
            // some values are `TRUE` or `FALSE`, in which case we use `GLboolean` instead of
            //  `GLenum`
            match ident.as_slice() {
                "TRUE" | "FALSE" => format!("{}GLboolean", types_prefix),
                _ => match enm.ty {
                    Some(ref s) if s.as_slice() == "ull" => format!("{}GLuint64", types_prefix),
                    _ => format!("{}GLenum", types_prefix)
                }
            }
        }
    };

    // computing the value of the enum
    let value = {
        // similar to the type, some values are `((Type)Value)`
        // replacing "((Type)Value)" by "Value as types::Type"
        if let Some((ty, val)) = val_regexed {
            format!("{} as {}{}", val, types_prefix, ty)
        } else {
            enm.value.clone()
        }
    };

    writeln!(dest, "\
        #[stable]
        #[allow(dead_code)]
        #[allow(non_upper_case_globals)]
        pub const {}: {} = {}; \
    ", ident, ty, value)
}

/// Generates all the type aliases for a namespace.
///
/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
///  things that we can't obtain from the XML files.
pub fn gen_type_aliases<W>(namespace: &Ns, dest: &mut W) -> IoResult<()> where W: Writer {
    match *namespace {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => {
            try!(ty::build_gl_aliases(dest));
        }

        Ns::Glx => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_x_aliases(dest));
            try!(ty::build_glx_aliases(dest));
        }

        Ns::Wgl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_win_aliases(dest));
            try!(ty::build_wgl_aliases(dest));
        }

        Ns::Egl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_egl_aliases(dest));
        }
    }

    Ok(())
}

/// Generates the list of Rust `Arg`s that a `Cmd` requires.
pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
    cmd.params.iter()
        .map(|binding| {
            // variable name of the binding
            let ident = match binding.ident.as_slice() {
                "in" => "in_",
                "ref" => "ref_",
                "type" => "type_",
                ident => ident,
            };

            // rust type of the binding
            let ty = ty::to_rust_ty(binding.ty.as_slice());

            // returning
            if with_idents && with_types {
                format!("{}: {}", ident, ty)
            } else if with_types {
                format!("{}", ty)
            } else if with_idents {
                format!("{}", ident)
            } else {
                panic!()
            }
        })
        .collect()
}

/// Generates the Rust return type of a `Cmd`.
pub fn gen_return_type(cmd: &Cmd) -> String {
    // turn the return type into a Rust type
    let ty = ty::to_rust_ty(cmd.proto.ty.as_slice());

    // ... but there is one more step: if the Rust type is `c_void`, we replace it with `()`
    if ty == "__gl_imports::libc::c_void" {
        return "()".to_string();
    }

    ty.to_string()
}

/// Generates the native symbol name of a `Cmd`.
///
/// Example results: `"glClear"`, `"wglCreateContext"`, etc.
pub fn gen_symbol_name(ns: &Ns, cmd: &str) -> String {
    (match *ns {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => "gl",
        Ns::Glx => "glX",
        Ns::Wgl => "wgl",
        Ns::Egl => "egl",
    }).to_string() + cmd
}
<|endoftext|>


<commit_before>use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
use event::{Event, WindowEvent};
use icon::Icon;
use monitor::{MonitorHandle as RootMH};
use window::{CreationError, MouseCursor, WindowAttributes, WindowId as RootWI};
use super::{EventLoopWindowTarget, register};
use std::collections::VecDeque;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::cell::RefCell;
use stdweb::{
    traits::*,
    unstable::TryInto
};
use stdweb::web::{
    document,
    html_element::CanvasElement,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MonitorHandle;

impl MonitorHandle {
    pub fn get_hidpi_factor(&self) -> f64 {
        // TODO
        1.0
    }

    pub fn get_position(&self) -> PhysicalPosition {
        unimplemented!();
    }

    pub fn get_dimensions(&self) -> PhysicalSize {
        unimplemented!();
    }

    pub fn get_name(&self) -> Option<String> {
        unimplemented!();
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificWindowBuilderAttributes;

impl WindowId {
    pub unsafe fn dummy() -> WindowId {
        WindowId
    }
}

pub struct Window {
    pub(crate) canvas: CanvasElement,
    pub(crate) redraw: Box<dyn Fn()>,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

impl Window {
    pub fn new<T>(target: &EventLoopWindowTarget<T>, attr: WindowAttributes,
                  _: PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError> {
        let element = document()
            .create_element("canvas")
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        let canvas: CanvasElement = element.try_into()
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        document().body()
            .ok_or_else(|| CreationError::OsError("Failed to find body node".to_owned()))?
            .append_child(&canvas);

        register(&target.runner, &canvas);

        let runner = target.runner.clone();
        let redraw = Box::new(move || runner.send_event(Event::WindowEvent {
            window_id: RootWI(WindowId),
            event: WindowEvent::RedrawRequested
        }));

        let window = Window {
            canvas,
            redraw,
            previous_pointer: RefCell::new("auto"),
            position: RefCell::new(LogicalPosition {
                x: 0.0,
                y: 0.0
            })
        };

        if let Some(dimensions) = attr.dimensions {
            window.set_inner_size(dimensions);
        } else {
            window.set_inner_size(LogicalSize {
                width: 1024.0,
                height: 768.0,
            })
        }
        // TODO: most of these are no-op, but should they stay here just in case?
        window.set_min_dimensions(attr.min_dimensions);
        window.set_max_dimensions(attr.max_dimensions);
        window.set_resizable(attr.resizable);
        window.set_title(&attr.title);
        window.set_maximized(attr.maximized);
        if attr.visible {
            window.show();
        } else {
            window.hide();
        }
        //window.set_transparent(attr.transparent);
        window.set_decorations(attr.decorations);
        window.set_always_on_top(attr.always_on_top);
        window.set_window_icon(attr.window_icon);

        Ok(window)
    }

    pub fn set_title(&self, title: &str) {
        document().set_title(title);
    }

    pub fn show(&self) {
        // Intentionally a no-op
    }

    pub fn hide(&self) {
        // Intentionally a no-op
    }

    pub fn request_redraw(&self) {
        (self.redraw)();
    }

    pub fn get_position(&self) -> Option<LogicalPosition> {
        let bounds = self.canvas.get_bounding_client_rect();
        Some(LogicalPosition {
            x: bounds.get_x(),
            y: bounds.get_y(),
        })
    }

    pub fn get_inner_position(&self) -> Option<LogicalPosition> {
        Some(*self.position.borrow())
    }

    pub fn set_position(&self, position: LogicalPosition) {
        *self.position.borrow_mut() = position;
        self.canvas.set_attribute("position", "fixed")
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("left", &position.x.to_string())
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("top", &position.y.to_string())
            .expect("Setting the position for the canvas");
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn set_inner_size(&self, size: LogicalSize) {
        self.canvas.set_width(size.width as u32);
        self.canvas.set_height(size.height as u32);
    }

    #[inline]
    pub fn set_min_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_max_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_resizable(&self, _resizable: bool) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn get_hidpi_factor(&self) -> f64 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        let text = match cursor {
            MouseCursor::Default => "auto",
            MouseCursor::Crosshair => "crosshair",
            MouseCursor::Hand => "pointer",
            MouseCursor::Arrow => "default",
            MouseCursor::Move => "move",
            MouseCursor::Text => "text",
            MouseCursor::Wait => "wait",
            MouseCursor::Help => "help",
            MouseCursor::Progress => "progress",

            MouseCursor::NotAllowed => "not-allowed",
            MouseCursor::ContextMenu => "context-menu",
            MouseCursor::Cell => "cell",
            MouseCursor::VerticalText => "vertical-text",
            MouseCursor::Alias => "alias",
            MouseCursor::Copy => "copy",
            MouseCursor::NoDrop => "no-drop",
            MouseCursor::Grab => "grab",
            MouseCursor::Grabbing => "grabbing",
            MouseCursor::AllScroll => "all-scroll",
            MouseCursor::ZoomIn => "zoom-in",
            MouseCursor::ZoomOut => "zoom-out",

            MouseCursor::EResize => "e-resize",
            MouseCursor::NResize => "n-resize",
            MouseCursor::NeResize => "ne-resize",
            MouseCursor::NwResize => "nw-resize",
            MouseCursor::SResize => "s-resize",
            MouseCursor::SeResize => "se-resize",
            MouseCursor::SwResize => "sw-resize",
            MouseCursor::WResize => "w-resize",
            MouseCursor::EwResize => "ew-resize",
            MouseCursor::NsResize => "ns-resize",
            MouseCursor::NeswResize => "nesw-resize",
            MouseCursor::NwseResize => "nwse-resize",
            MouseCursor::ColResize => "col-resize",
            MouseCursor::RowResize => "row-resize",
        };
        *self.previous_pointer.borrow_mut() = text;
        self.canvas.set_attribute("cursor", text)
            .expect("Setting the cursor on the canvas");
    }

    #[inline]
    pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn grab_cursor(&self, _grab: bool) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn hide_cursor(&self, hide: bool) {
        if hide {
            self.canvas.set_attribute("cursor", "none")
                .expect("Setting the cursor on the canvas");
        } else {
            self.canvas.set_attribute("cursor", *self.previous_pointer.borrow())
                .expect("Setting the cursor on the canvas");
        }
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_decorations(&self, _decorations: bool) {
        // Intentionally a no-op, no canvas decorations
    }

    #[inline]
    pub fn set_always_on_top(&self, _always_on_top: bool) {
        // Intentionally a no-op, no window ordering
    }

    #[inline]
    pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
        // TODO: should this set the favicon?
    }

    #[inline]
    pub fn set_ime_spot(&self, _position: LogicalPosition) {
        // TODO: what is this?
    }

    #[inline]
    pub fn get_current_monitor(&self) -> RootMH {
        RootMH {
            inner: MonitorHandle
        }
    }

    #[inline]
    pub fn get_available_monitors(&self) -> VecDequeIter<MonitorHandle> {
        VecDeque::new().into_iter()
    }

    #[inline]
    pub fn get_primary_monitor(&self) -> MonitorHandle {
        MonitorHandle
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        // TODO ?
        unsafe { WindowId::dummy() }
    }
}
<commit_msg>Only send the request-redraw on the next animation frame<commit_after>use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
use event::{Event, WindowEvent};
use icon::Icon;
use monitor::{MonitorHandle as RootMH};
use window::{CreationError, MouseCursor, WindowAttributes, WindowId as RootWI};
use super::{EventLoopWindowTarget, register};
use std::collections::VecDeque;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::cell::RefCell;
use stdweb::{
    traits::*,
    unstable::TryInto
};
use stdweb::web::{
    document, window,
    html_element::CanvasElement,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MonitorHandle;

impl MonitorHandle {
    pub fn get_hidpi_factor(&self) -> f64 {
        1.0
    }

    pub fn get_position(&self) -> PhysicalPosition {
        unimplemented!();
    }

    pub fn get_dimensions(&self) -> PhysicalSize {
        unimplemented!();
    }

    pub fn get_name(&self) -> Option<String> {
        unimplemented!();
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificWindowBuilderAttributes;

impl WindowId {
    pub unsafe fn dummy() -> WindowId {
        WindowId
    }
}

pub struct Window {
    pub(crate) canvas: CanvasElement,
    pub(crate) redraw: Box<dyn Fn()>,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

impl Window {
    pub fn new<T>(target: &EventLoopWindowTarget<T>, attr: WindowAttributes,
                  _: PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError> {
        let element = document()
            .create_element("canvas")
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        let canvas: CanvasElement = element.try_into()
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        document().body()
            .ok_or_else(|| CreationError::OsError("Failed to find body node".to_owned()))?
            .append_child(&canvas);

        register(&target.runner, &canvas);

        let runner = target.runner.clone();
        let redraw = Box::new(move || window().request_animation_frame(|| runner.send_event(Event::WindowEvent {
            window_id: RootWI(WindowId),
            event: WindowEvent::RedrawRequested
        })));

        let window = Window {
            canvas,
            redraw,
            previous_pointer: RefCell::new("auto"),
            position: RefCell::new(LogicalPosition {
                x: 0.0,
                y: 0.0
            })
        };

        if let Some(dimensions) = attr.dimensions {
            window.set_inner_size(dimensions);
        } else {
            window.set_inner_size(LogicalSize {
                width: 1024.0,
                height: 768.0,
            })
        }
        window.set_min_dimensions(attr.min_dimensions);
        window.set_max_dimensions(attr.max_dimensions);
        window.set_resizable(attr.resizable);
        window.set_title(&attr.title);
        window.set_maximized(attr.maximized);
        if attr.visible {
            window.show();
        } else {
            window.hide();
        }
        //window.set_transparent(attr.transparent);
        window.set_decorations(attr.decorations);
        window.set_always_on_top(attr.always_on_top);
        window.set_window_icon(attr.window_icon);

        Ok(window)
    }

    pub fn set_title(&self, title: &str) {
        document().set_title(title);
    }

    pub fn show(&self) {
        // Intentionally a no-op
    }

    pub fn hide(&self) {
        // Intentionally a no-op
    }

    pub fn request_redraw(&self) {
        (self.redraw)();
    }

    pub fn get_position(&self) -> Option<LogicalPosition> {
        let bounds = self.canvas.get_bounding_client_rect();
        Some(LogicalPosition {
            x: bounds.get_x(),
            y: bounds.get_y(),
        })
    }

    pub fn get_inner_position(&self) -> Option<LogicalPosition> {
        Some(*self.position.borrow())
    }

    pub fn set_position(&self, position: LogicalPosition) {
        *self.position.borrow_mut() = position;
        self.canvas.set_attribute("position", "fixed")
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("left", &position.x.to_string())
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("top", &position.y.to_string())
            .expect("Setting the position for the canvas");
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn set_inner_size(&self, size: LogicalSize) {
        self.canvas.set_width(size.width as u32);
        self.canvas.set_height(size.height as u32);
    }

    #[inline]
    pub fn set_min_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_max_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_resizable(&self, _resizable: bool) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn get_hidpi_factor(&self) -> f64 {
        1.0
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        let text = match cursor {
            MouseCursor::Default => "auto",
            MouseCursor::Crosshair => "crosshair",
            MouseCursor::Hand => "pointer",
            MouseCursor::Arrow => "default",
            MouseCursor::Move => "move",
            MouseCursor::Text => "text",
            MouseCursor::Wait => "wait",
            MouseCursor::Help => "help",
            MouseCursor::Progress => "progress",

            MouseCursor::NotAllowed => "not-allowed",
            MouseCursor::ContextMenu => "context-menu",
            MouseCursor::Cell => "cell",
            MouseCursor::VerticalText => "vertical-text",
            MouseCursor::Alias => "alias",
            MouseCursor::Copy => "copy",
            MouseCursor::NoDrop => "no-drop",
            MouseCursor::Grab => "grab",
            MouseCursor::Grabbing => "grabbing",
            MouseCursor::AllScroll => "all-scroll",
            MouseCursor::ZoomIn => "zoom-in",
            MouseCursor::ZoomOut => "zoom-out",

            MouseCursor::EResize => "e-resize",
            MouseCursor::NResize => "n-resize",
            MouseCursor::NeResize => "ne-resize",
            MouseCursor::NwResize => "nw-resize",
            MouseCursor::SResize => "s-resize",
            MouseCursor::SeResize => "se-resize",
            MouseCursor::SwResize => "sw-resize",
            MouseCursor::WResize => "w-resize",
            MouseCursor::EwResize => "ew-resize",
            MouseCursor::NsResize => "ns-resize",
            MouseCursor::NeswResize => "nesw-resize",
            MouseCursor::NwseResize => "nwse-resize",
            MouseCursor::ColResize => "col-resize",
            MouseCursor::RowResize => "row-resize",
        };
        *self.previous_pointer.borrow_mut() = text;
        self.canvas.set_attribute("cursor", text)
            .expect("Setting the cursor on the canvas");
    }

    #[inline]
    pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn grab_cursor(&self, _grab: bool) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn hide_cursor(&self, hide: bool) {
        if hide {
            self.canvas.set_attribute("cursor", "none")
                .expect("Setting the cursor on the canvas");
        } else {
            self.canvas.set_attribute("cursor", *self.previous_pointer.borrow())
                .expect("Setting the cursor on the canvas");
        }
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_decorations(&self, _decorations: bool) {
        // Intentionally a no-op, no canvas decorations
    }

    #[inline]
    pub fn set_always_on_top(&self, _always_on_top: bool) {
        // Intentionally a no-op, no window ordering
    }

    #[inline]
    pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
        // Currently an intentional no-op
    }

    #[inline]
    pub fn set_ime_spot(&self, _position: LogicalPosition) {
        // TODO: what is this?
    }

    #[inline]
    pub fn get_current_monitor(&self) -> RootMH {
        RootMH {
            inner: MonitorHandle
        }
    }

    #[inline]
    pub fn get_available_monitors(&self) -> VecDequeIter<MonitorHandle> {
        VecDeque::new().into_iter()
    }

    #[inline]
    pub fn get_primary_monitor(&self) -> MonitorHandle {
        MonitorHandle
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        // TODO ?
        unsafe { WindowId::dummy() }
    }
}
<|endoftext|>


<commit_before>use super::shapes::*;
use super::well::Y_OFFSET;
use super::BLOCK_SIZE;
use ggez::graphics::{Color, DrawParam, Point2};
use ggez::{graphics, Context, GameResult};

/// A `PieceShape` is a 4x4 array that represents the shape of a piece. A 0 is
/// an empty space while a 1 is solid.
pub type PieceShape = [[u32; 4]; 4];

/// All the possible piece types that can be taken out of `PieceBag`.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PieceType {
    L,
    T,
    I,
    Z,
    J,
    S,
    O,
}

/// The tetromino piece that the player controls.
pub struct Piece {
    shape: PieceShape,
    shape_type: PieceType,
    current_rotation_index: u32,
    pub top_left: Point2,
    pub potential_top_left: Point2,
    shadow_position: Point2,
}

impl Piece {
    /// Creates a new piece of type `PieceType`.
    pub fn new(shape_type: PieceType) -> Self {
        let shape = piece_type_to_shape(shape_type, 0);

        Piece {
            shape,
            shape_type,
            top_left: Point2::new(3.0, 0.0),
            potential_top_left: Point2::new(3.0, 0.0),
            shadow_position: Point2::new(3.0, 0.0),
            current_rotation_index: 0,
        }
    }

    // I don't remember why I did this.
    /// Create a new piece from a reference of a `PieceType`.
    pub fn new_from_ref(shape_type: PieceType) -> Self {
        let shape = piece_type_to_shape(shape_type, 0);

        Piece {
            shape,
            shape_type,
            top_left: Point2::new(3.0, 0.0),
            potential_top_left: Point2::new(3.0, 0.0),
            shadow_position: Point2::new(3.0, 0.0),
            current_rotation_index: 0,
        }
    }

    /// Draw the current piece.
    pub fn draw(&self, ctx: &mut Context, image: &graphics::Image) -> GameResult<()> {
        // get starting position to draw window
        // TODO: doing all of this work every frame seems bad
        let width = graphics::get_screen_coordinates(ctx).w;
        let middle = width / 2.0;
        let starting_pos = middle - ((BLOCK_SIZE as f32 * 10.0) / 2.0);

        for (r, _) in self.shape.iter().enumerate() {
            for (c, _) in self.shape[r].iter().enumerate() {
                if self.shape[r][c] != 0 {
                    if r + (self.top_left.y as usize) < 2 {
                        // don't draw in vanish zone
                        continue;
                    }
                    let colour = block_to_colour(self.shape[r][c], false);
                    graphics::set_color(ctx, colour)?;

                    let x = starting_pos + ((c as f32 + self.top_left.x as f32) * BLOCK_SIZE);
                    let y = Y_OFFSET + ((r as f32 + self.top_left.y as f32) * BLOCK_SIZE) as f32;

                    graphics::draw(ctx, image, Point2::new(x, y), 0.0)?;
                }
            }
        }

        Ok(())
    }

    /// Draw the current piece's shadow.
    pub fn draw_shadow(
        &self,
        ctx: &mut Context,
        image: &graphics::Image,
        shadow_position: Point2,
    ) -> GameResult<()> {
        // get starting position to draw window
        // TODO: doing all of this work every frame seems bad
        let width = graphics::get_screen_coordinates(ctx).w;
        let middle = width / 2.0;
        let starting_pos = middle - ((BLOCK_SIZE as f32 * 10.0) / 2.0);

        for (r, _) in self.shape.iter().enumerate() {
            for (c, _) in self.shape[r].iter().enumerate() {
                if self.shape[r][c] != 0 {
                    let colour = block_to_colour(self.shape[r][c], true);
                    graphics::set_color(ctx, colour)?;

                    let x = starting_pos + ((c as f32 + shadow_position.x as f32) * BLOCK_SIZE);
                    let y = Y_OFFSET + ((r as f32 + shadow_position.y as f32) * BLOCK_SIZE) as f32;

                    graphics::draw(ctx, image, Point2::new(x, y), 0.0)?;
                }
            }
        }

        Ok(())
    }

    /// Draw the current piece outside of the grid at a given point.
    pub fn draw_at_point(
        &self,
        ctx: &mut Context,
        image: &graphics::Image,
        top_left: Point2,
        rotation: f64,
    ) -> GameResult<()> {
        let starting_pos = top_left;
        // get the centre of our complex object in order to rotate around it
        let centre = Point2::new(
            starting_pos.x + (BLOCK_SIZE * 8.0) / 2.0,
            starting_pos.y + (BLOCK_SIZE * 8.0) / 2.0,
        );

        for (r, _) in self.shape.iter().enumerate() {
            for (c, _) in self.shape[r].iter().enumerate() {
                if self.shape[r][c] != 0 {
                    let colour = block_to_colour(self.shape[r][c], false);
                    graphics::set_color(ctx, colour)?;

                    let mut x = starting_pos.x as f32 + ((c as f32 + 1.0) * BLOCK_SIZE);
                    let mut y = starting_pos.y as f32 + (r as f32 * BLOCK_SIZE);

                    let sin = rotation.sin() as f32;
                    let cos = rotation.cos() as f32;

                    // translate to origin
                    x -= centre.x;
                    y -= centre.y;

                    // rotate
                    let xnew = x * cos - y * sin;
                    let ynew = x * sin + y * cos;

                    // translate point back
                    x = xnew + centre.x;
                    y = ynew + centre.y;

                    let draw_param = DrawParam {
                        dest: Point2::new(x, y),
                        rotation: rotation as f32,
                        ..Default::default()
                    };

                    graphics::draw_ex(ctx, image, draw_param)?;
                }
            }
        }

        // TODO: global debug flag to control whether this appears or not,
        // should be able to toggle via an environmental variable for ease-of-use

        // graphics::set_color(ctx, Color::new(255.0, 0.0, 0.0, 255.0))?;
        // graphics::circle(ctx, graphics::DrawMode::Fill, centre, 2.0, 22)?;
        // graphics::set_color(ctx, Color::new(0.0, 0.0, 255.0, 255.0))?;
        // graphics::circle(ctx, graphics::DrawMode::Fill, top_left, 2.0, 22)?;

        Ok(())
    }

    /// Return what the next shape of the current piece would be given a
    /// particular rotation `direction` (-1 for left, 1 for right)
    pub fn get_next_shape(&self, direction: i32) -> PieceShape {
        let next_index = next_rotation_index(self.current_rotation_index, direction);

        piece_type_to_shape(self.shape_type, next_index as usize)
    }

    /// Returns the current piece's shape.
    pub fn get_shape(&self) -> PieceShape {
        self.shape
    }

    /// Returns the current piece's type.
    pub fn get_type(&self) -> PieceType {
        self.shape_type
    }

    /// Given a direction, change the current piece's shape.
    pub fn change_shape(&mut self, direction: i32) {
        let next_index = next_rotation_index(self.current_rotation_index, direction);

        self.shape = piece_type_to_shape(self.shape_type, next_index as usize);
        self.current_rotation_index = next_index;
    }

    /// Set the current piece's shadow position.
    pub fn set_shadow_position(&mut self, shadow_pos: Point2) {
        self.shadow_position = shadow_pos;
    }

    /// Get the current piece's shadow position.
    pub fn get_shadow_position(&self) -> Point2 {
        self.shadow_position
    }
}

/*
 * Utility methods
*/

/// Given a type of piece, return the shape at the given rotation index.
pub fn piece_type_to_shape(shape: PieceType, index: usize) -> PieceShape {
    match shape {
        PieceType::O => O_SHAPES[index],
        PieceType::J => J_SHAPES[index],
        PieceType::I => I_SHAPES[index],
        PieceType::S => S_SHAPES[index],
        PieceType::Z => Z_SHAPES[index],
        PieceType::L => L_SHAPES[index],
        PieceType::T => T_SHAPES[index],
    }
}

/// Given an integer that represents a type of piece, return the `PieceType`.
pub fn u8_to_piece_type(num: u8) -> Option<PieceType> {
    match num {
        0 => Some(PieceType::I),
        1 => Some(PieceType::J),
        2 => Some(PieceType::L),
        3 => Some(PieceType::O),
        4 => Some(PieceType::S),
        5 => Some(PieceType::T),
        6 => Some(PieceType::Z),
        _ => unreachable!(),
    }
}

/// Get the block colour depending on the shape. If `shadow` is true, the
/// colour's alpha channel is reduced.
pub fn block_to_colour(num: u32, shadow: bool) -> Color {
    if shadow {
        match num {
            1 => Color::from((0, 255, 255, 75)),
            2 => Color::from((0, 0, 255, 75)),
            3 => Color::from((255, 165, 0, 75)),
            4 => Color::from((255, 255, 0, 75)),
            5 => Color::from((128, 255, 0, 75)),
            6 => Color::from((128, 0, 128, 75)),
            7 => Color::from((255, 0, 0, 75)),
            _ => unreachable!(),
        }
    } else {
        match num {
            1 => Color::from((0, 255, 255, 255)),
            2 => Color::from((0, 0, 255, 255)),
            3 => Color::from((255, 165, 0, 255)),
            4 => Color::from((255, 255, 0, 255)),
            5 => Color::from((128, 255, 0, 255)),
            6 => Color::from((128, 0, 128, 255)),
            7 => Color::from((255, 0, 0, 255)),
            _ => unreachable!(),
        }
    }
}

/// Return the index of the next rotation shape, given the current rotation
/// shape's index and a direction.
pub fn next_rotation_index(current_index: u32, direction: i32) -> u32 {
    if direction == -1 {
        match current_index {
            0 => 1,
            1 => 2,
            2 => 3,
            3 => 0,
            _ => unreachable!(),
        }
    } else {
        match current_index {
            0 => 3,
            1 => 0,
            2 => 1,
            3 => 2,
            _ => unreachable!(),
        }
    }
}
<commit_msg>Update tetromino colours<commit_after>use super::shapes::*;
use super::well::Y_OFFSET;
use super::BLOCK_SIZE;
use ggez::graphics::{Color, DrawParam, Point2};
use ggez::{graphics, Context, GameResult};

/// A `PieceShape` is a 4x4 array that represents the shape of a piece. A 0 is
/// an empty space while a 1 is solid.
pub type PieceShape = [[u32; 4]; 4];

/// All the possible piece types that can be taken out of `PieceBag`.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PieceType {
    L,
    T,
    I,
    Z,
    J,
    S,
    O,
}

/// The tetromino piece that the player controls.
pub struct Piece {
    shape: PieceShape,
    shape_type: PieceType,
    current_rotation_index: u32,
    pub top_left: Point2,
    pub potential_top_left: Point2,
    shadow_position: Point2,
}

impl Piece {
    /// Creates a new piece of type `PieceType`.
    pub fn new(shape_type: PieceType) -> Self {
        let shape = piece_type_to_shape(shape_type, 0);

        Piece {
            shape,
            shape_type,
            top_left: Point2::new(3.0, 0.0),
            potential_top_left: Point2::new(3.0, 0.0),
            shadow_position: Point2::new(3.0, 0.0),
            current_rotation_index: 0,
        }
    }

    // I don't remember why I did this.
    /// Create a new piece from a reference of a `PieceType`.
    pub fn new_from_ref(shape_type: PieceType) -> Self {
        let shape = piece_type_to_shape(shape_type, 0);

        Piece {
            shape,
            shape_type,
            top_left: Point2::new(3.0, 0.0),
            potential_top_left: Point2::new(3.0, 0.0),
            shadow_position: Point2::new(3.0, 0.0),
            current_rotation_index: 0,
        }
    }

    /// Draw the current piece.
    pub fn draw(&self, ctx: &mut Context, image: &graphics::Image) -> GameResult<()> {
        // get starting position to draw window
        // TODO: doing all of this work every frame seems bad
        let width = graphics::get_screen_coordinates(ctx).w;
        let middle = width / 2.0;
        let starting_pos = middle - ((BLOCK_SIZE as f32 * 10.0) / 2.0);

        for (r, _) in self.shape.iter().enumerate() {
            for (c, _) in self.shape[r].iter().enumerate() {
                if self.shape[r][c] != 0 {
                    if r + (self.top_left.y as usize) < 2 {
                        // don't draw in vanish zone
                        continue;
                    }
                    let colour = block_to_colour(self.shape[r][c], false);
                    graphics::set_color(ctx, colour)?;

                    let x = starting_pos + ((c as f32 + self.top_left.x as f32) * BLOCK_SIZE);
                    let y = Y_OFFSET + ((r as f32 + self.top_left.y as f32) * BLOCK_SIZE) as f32;

                    graphics::draw(ctx, image, Point2::new(x, y), 0.0)?;
                }
            }
        }

        Ok(())
    }

    /// Draw the current piece's shadow.
    pub fn draw_shadow(
        &self,
        ctx: &mut Context,
        image: &graphics::Image,
        shadow_position: Point2,
    ) -> GameResult<()> {
        // get starting position to draw window
        // TODO: doing all of this work every frame seems bad
        let width = graphics::get_screen_coordinates(ctx).w;
        let middle = width / 2.0;
        let starting_pos = middle - ((BLOCK_SIZE as f32 * 10.0) / 2.0);

        for (r, _) in self.shape.iter().enumerate() {
            for (c, _) in self.shape[r].iter().enumerate() {
                if self.shape[r][c] != 0 {
                    let colour = block_to_colour(self.shape[r][c], true);
                    graphics::set_color(ctx, colour)?;

                    let x = starting_pos + ((c as f32 + shadow_position.x as f32) * BLOCK_SIZE);
                    let y = Y_OFFSET + ((r as f32 + shadow_position.y as f32) * BLOCK_SIZE) as f32;

                    graphics::draw(ctx, image, Point2::new(x, y), 0.0)?;
                }
            }
        }

        Ok(())
    }

    /// Draw the current piece outside of the grid at a given point.
    pub fn draw_at_point(
        &self,
        ctx: &mut Context,
        image: &graphics::Image,
        top_left: Point2,
        rotation: f64,
    ) -> GameResult<()> {
        let starting_pos = top_left;
        // get the centre of our complex object in order to rotate around it
        let centre = Point2::new(
            starting_pos.x + (BLOCK_SIZE * 8.0) / 2.0,
            starting_pos.y + (BLOCK_SIZE * 8.0) / 2.0,
        );

        for (r, _) in self.shape.iter().enumerate() {
            for (c, _) in self.shape[r].iter().enumerate() {
                if self.shape[r][c] != 0 {
                    let colour = block_to_colour(self.shape[r][c], false);
                    graphics::set_color(ctx, colour)?;

                    let mut x = starting_pos.x as f32 + ((c as f32 + 1.0) * BLOCK_SIZE);
                    let mut y = starting_pos.y as f32 + (r as f32 * BLOCK_SIZE);

                    let sin = rotation.sin() as f32;
                    let cos = rotation.cos() as f32;

                    // translate to origin
                    x -= centre.x;
                    y -= centre.y;

                    // rotate
                    let xnew = x * cos - y * sin;
                    let ynew = x * sin + y * cos;

                    // translate point back
                    x = xnew + centre.x;
                    y = ynew + centre.y;

                    let draw_param = DrawParam {
                        dest: Point2::new(x, y),
                        rotation: rotation as f32,
                        ..Default::default()
                    };

                    graphics::draw_ex(ctx, image, draw_param)?;
                }
            }
        }

        // TODO: global debug flag to control whether this appears or not,
        // should be able to toggle via an environmental variable for ease-of-use

        // graphics::set_color(ctx, Color::new(255.0, 0.0, 0.0, 255.0))?;
        // graphics::circle(ctx, graphics::DrawMode::Fill, centre, 2.0, 22)?;
        // graphics::set_color(ctx, Color::new(0.0, 0.0, 255.0, 255.0))?;
        // graphics::circle(ctx, graphics::DrawMode::Fill, top_left, 2.0, 22)?;

        Ok(())
    }

    /// Return what the next shape of the current piece would be given a
    /// particular rotation `direction` (-1 for left, 1 for right)
    pub fn get_next_shape(&self, direction: i32) -> PieceShape {
        let next_index = next_rotation_index(self.current_rotation_index, direction);

        piece_type_to_shape(self.shape_type, next_index as usize)
    }

    /// Returns the current piece's shape.
    pub fn get_shape(&self) -> PieceShape {
        self.shape
    }

    /// Returns the current piece's type.
    pub fn get_type(&self) -> PieceType {
        self.shape_type
    }

    /// Given a direction, change the current piece's shape.
    pub fn change_shape(&mut self, direction: i32) {
        let next_index = next_rotation_index(self.current_rotation_index, direction);

        self.shape = piece_type_to_shape(self.shape_type, next_index as usize);
        self.current_rotation_index = next_index;
    }

    /// Set the current piece's shadow position.
    pub fn set_shadow_position(&mut self, shadow_pos: Point2) {
        self.shadow_position = shadow_pos;
    }

    /// Get the current piece's shadow position.
    pub fn get_shadow_position(&self) -> Point2 {
        self.shadow_position
    }
}

/*
 * Utility methods
*/

/// Given a type of piece, return the shape at the given rotation index.
pub fn piece_type_to_shape(shape: PieceType, index: usize) -> PieceShape {
    match shape {
        PieceType::O => O_SHAPES[index],
        PieceType::J => J_SHAPES[index],
        PieceType::I => I_SHAPES[index],
        PieceType::S => S_SHAPES[index],
        PieceType::Z => Z_SHAPES[index],
        PieceType::L => L_SHAPES[index],
        PieceType::T => T_SHAPES[index],
    }
}

/// Given an integer that represents a type of piece, return the `PieceType`.
pub fn u8_to_piece_type(num: u8) -> Option<PieceType> {
    match num {
        0 => Some(PieceType::I),
        1 => Some(PieceType::J),
        2 => Some(PieceType::L),
        3 => Some(PieceType::O),
        4 => Some(PieceType::S),
        5 => Some(PieceType::T),
        6 => Some(PieceType::Z),
        _ => unreachable!(),
    }
}

/// Get the block colour depending on the shape. If `shadow` is true, the
/// colour's alpha channel is reduced.
pub fn block_to_colour(num: u32, shadow: bool) -> Color {
    if shadow {
        match num {
            1 => Color::from((0, 255, 255, 75)),   // I
            2 => Color::from((128, 70, 255, 130)), // J
            3 => Color::from((255, 165, 0, 75)),   // L
            4 => Color::from((255, 255, 0, 75)),   // O
            5 => Color::from((128, 255, 0, 75)),   // S
            6 => Color::from((255, 128, 128, 75)), // T
            7 => Color::from((255, 0, 0, 75)),     // Z
            _ => unreachable!(),
        }
    } else {
        match num {
            1 => Color::from((0, 255, 255, 255)),   // I
            2 => Color::from((128, 70, 255, 255)),  // J
            3 => Color::from((255, 165, 0, 255)),   // L
            4 => Color::from((255, 255, 0, 255)),   // O
            5 => Color::from((128, 255, 0, 255)),   // S
            6 => Color::from((255, 128, 128, 255)), // T
            7 => Color::from((255, 0, 0, 255)),     // Z
            _ => unreachable!(),
        }
    }
}

/// Return the index of the next rotation shape, given the current rotation
/// shape's index and a direction.
pub fn next_rotation_index(current_index: u32, direction: i32) -> u32 {
    if direction == -1 {
        match current_index {
            0 => 1,
            1 => 2,
            2 => 3,
            3 => 0,
            _ => unreachable!(),
        }
    } else {
        match current_index {
            0 => 3,
            1 => 0,
            2 => 1,
            3 => 2,
            _ => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>//! Cache the pipeline objects to disk for faster reloads.
//!
//! A pipeline cache is an opaque type that allow you to cache your graphics and compute
//! pipelines on the disk.
//!
//! You can create either an empty cache or a cache from some initial data. Whenever you create a
//! graphics or compute pipeline, you have the possibility to pass a reference to that cache.
//! The Vulkan implementation will then look in the cache for an existing entry, or add one if it
//! doesn't exist.
//!
//! Once that is done, you can extract the data from the cache and store it.
//!
use std::mem;
use std::ptr;
use std::sync::Arc;

use device::Device;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Opaque cache that contains pipeline objects.
pub struct PipelineCache {
    device: Arc<Device>,
    cache: vk::PipelineCache,
}

impl PipelineCache {
    /// Builds a new pipeline cache.
    ///
    /// You can pass optional data to initialize the cache with. If you don't pass any data, the
    /// cache will be empty.
    // TODO: is that unsafe? is it safe to pass garbage data?
    pub unsafe fn new(device: &Arc<Device>, initial_data: Option<&[u8]>)
                      -> Result<Arc<PipelineCache>, OomError>
    {
        let vk = device.pointers();

        let cache = {
            let infos = vk::PipelineCacheCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                initialDataSize: initial_data.map(|d| d.len()).unwrap_or(0),
                pInitialData: initial_data.map(|d| d.as_ptr() as *const _).unwrap_or(ptr::null()),
            };

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

        Ok(Arc::new(PipelineCache {
            device: device.clone(),
            cache: cache,
        }))
    }

    /// Merges other pipeline caches into this one.
    ///
    /// # Panic
    ///
    /// - Panicks if `self` is included in the list of other pipelines.
    ///
    pub fn merge<'a, I>(&self, pipelines: I) -> Result<(), OomError>
        where I: IntoIterator<Item = &'a &'a Arc<PipelineCache>>
    {
        unsafe {
            let vk = self.device.pointers();

            let pipelines = pipelines.into_iter().map(|pipeline| {
                assert!(&***pipeline as *const _ != &*self as *const _);
                pipeline.cache
            }).collect::<Vec<_>>();

            try!(check_errors(vk.MergePipelineCaches(self.device.internal_object(), self.cache,
                                                     pipelines.len() as u32, pipelines.as_ptr())));

            Ok(())
        }
    }

    /// Obtains the data from the cache.
    ///
    /// This data can be stored and then reloaded and passed to `PipelineCache::new`.
    pub fn get_data(&self) -> Result<Vec<u8>, OomError> {
        unsafe {
            let vk = self.device.pointers();

            let mut num = 0;
            try!(check_errors(vk.GetPipelineCacheData(self.device.internal_object(), self.cache,
                                                      &mut num, ptr::null_mut())));

            let mut data: Vec<u8> = Vec::with_capacity(num as usize);
            try!(check_errors(vk.GetPipelineCacheData(self.device.internal_object(), self.cache,
                                                      &mut num, data.as_mut_ptr() as *mut _)));
            data.set_len(num as usize);

            Ok(data)
        }
    }
}

unsafe impl VulkanObject for PipelineCache {
    type Object = vk::PipelineCache;

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

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

#[cfg(test)]
mod tests {
    #[test]
    //#[should_panic]
    fn merge_self() {
        let instance = instance!();

        // let pipeline = PipelineCache::new(&device).unwrap();
        // pipeline.merge(&[&pipeline]).unwrap();
    }
}
<commit_msg>Minor PipelineCache reorganization<commit_after>//! Cache the pipeline objects to disk for faster reloads.
//!
//! A pipeline cache is an opaque type that allow you to cache your graphics and compute
//! pipelines on the disk.
//!
//! You can create either an empty cache or a cache from some initial data. Whenever you create a
//! graphics or compute pipeline, you have the possibility to pass a reference to that cache.
//! The Vulkan implementation will then look in the cache for an existing entry, or add one if it
//! doesn't exist.
//!
//! Once that is done, you can extract the data from the cache and store it.
//!
use std::mem;
use std::ptr;
use std::sync::Arc;

use device::Device;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Opaque cache that contains pipeline objects.
pub struct PipelineCache {
    device: Arc<Device>,
    cache: vk::PipelineCache,
}

impl PipelineCache {
    /// Builds a new pipeline cache from existing data.
    ///
    /// The data must have been previously obtained with `get_data`.
    // TODO: is that unsafe? is it safe to pass garbage data?
    pub unsafe fn with_data(device: &Arc<Device>, initial_data: &[u8])
                            -> Result<Arc<PipelineCache>, OomError>
    {
        PipelineCache::new_impl(device, Some(initial_data))
    }

    /// Builds a new empty pipeline cache.
    pub fn empty(device: &Arc<Device>) -> Result<Arc<PipelineCache>, OomError> {
        unsafe { PipelineCache::new_impl(device, None) }
    }

    unsafe fn new_impl(device: &Arc<Device>, initial_data: Option<&[u8]>)
                       -> Result<Arc<PipelineCache>, OomError>
    {
        let vk = device.pointers();

        let cache = {
            let infos = vk::PipelineCacheCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                initialDataSize: initial_data.map(|d| d.len()).unwrap_or(0),
                pInitialData: initial_data.map(|d| d.as_ptr() as *const _).unwrap_or(ptr::null()),
            };

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

        Ok(Arc::new(PipelineCache {
            device: device.clone(),
            cache: cache,
        }))
    }

    /// Merges other pipeline caches into this one.
    ///
    /// # Panic
    ///
    /// - Panicks if `self` is included in the list of other pipelines.
    ///
    pub fn merge<'a, I>(&self, pipelines: I) -> Result<(), OomError>
        where I: IntoIterator<Item = &'a &'a Arc<PipelineCache>>
    {
        unsafe {
            let vk = self.device.pointers();

            let pipelines = pipelines.into_iter().map(|pipeline| {
                assert!(&***pipeline as *const _ != &*self as *const _);
                pipeline.cache
            }).collect::<Vec<_>>();

            try!(check_errors(vk.MergePipelineCaches(self.device.internal_object(), self.cache,
                                                     pipelines.len() as u32, pipelines.as_ptr())));

            Ok(())
        }
    }

    /// Obtains the data from the cache.
    ///
    /// This data can be stored and then reloaded and passed to `PipelineCache::new`.
    pub fn get_data(&self) -> Result<Vec<u8>, OomError> {
        unsafe {
            let vk = self.device.pointers();

            let mut num = 0;
            try!(check_errors(vk.GetPipelineCacheData(self.device.internal_object(), self.cache,
                                                      &mut num, ptr::null_mut())));

            let mut data: Vec<u8> = Vec::with_capacity(num as usize);
            try!(check_errors(vk.GetPipelineCacheData(self.device.internal_object(), self.cache,
                                                      &mut num, data.as_mut_ptr() as *mut _)));
            data.set_len(num as usize);

            Ok(data)
        }
    }
}

unsafe impl VulkanObject for PipelineCache {
    type Object = vk::PipelineCache;

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

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

#[cfg(test)]
mod tests {
    use pipeline::cache::PipelineCache;

    #[test]
    #[should_panic]
    fn merge_self_forbidden() {
        let (device, queue) = gfx_dev_and_queue!();
        let pipeline = PipelineCache::empty(&device).unwrap();
        pipeline.merge(&[&pipeline]).unwrap();
    }
}
<|endoftext|>


<commit_before>pub const PTHREAD_STACK_MIN: ::size_t = 2048;
pub const KERN_PROC_PATHNAME: ::c_int = 12;

extern {
    pub fn __error() -> *mut ::c_int;
}
<commit_msg>Fix SIGSTKSZ for FreeBSD<commit_after>pub const PTHREAD_STACK_MIN: ::size_t = 2048;
pub const KERN_PROC_PATHNAME: ::c_int = 12;
pub const SIGSTKSZ: ::size_t = 2048 /* MINSIGSTKSZ */ + 32768;

extern {
    pub fn __error() -> *mut ::c_int;
}
<|endoftext|>


<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use tink_core::{subtle::random::get_random_bytes, Mac, TinkError};
use tink_proto::HashType;

struct TestCase {
    hash_alg: HashType,
    tag_size: usize,
    key: &'static [u8],
    data: &'static [u8],
    expected_mac: &'static str,
}

const KEY: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
const DATA: &[u8] = b"Hello";

const HMAC_TESTS : &[TestCase] = &[
    TestCase {
        hash_alg:     HashType::Sha256,
        tag_size:     32,
        data:         DATA,
        key:          KEY,
        expected_mac: "e0ff02553d9a619661026c7aa1ddf59b7b44eac06a9908ff9e19961d481935d4",
    },
    TestCase {
        hash_alg:     HashType::Sha512,
        tag_size:     64,
        data:         DATA,
        key:          KEY,
        expected_mac: "481e10d823ba64c15b94537a3de3f253c16642451ac45124dd4dde120bf1e5c15e55487d55ba72b43039f235226e7954cd5854b30abc4b5b53171a4177047c9b",
    },
    // empty data
    TestCase {
        hash_alg:     HashType::Sha256,
        tag_size:     32,
        data:         &[],
        key:          KEY,
        expected_mac: "07eff8b326b7798c9ccfcbdbe579489ac785a7995a04618b1a2813c26744777d",
    },
];

#[test]
fn test_hmac_basic() {
    tink_mac::init();
    for (i, test) in HMAC_TESTS.iter().enumerate() {
        let cipher = tink_mac::subtle::Hmac::new(test.hash_alg, test.key, test.tag_size)
            .expect("cannot create new mac");
        let mac = cipher
            .compute_mac(test.data)
            .expect("mac computation failed");
        assert_eq!(
            hex::encode(&mac),
            test.expected_mac[..(test.tag_size * 2)],
            "incorrect mac in test case {}",
            i
        );
        cipher
            .verify_mac(&mac, test.data)
            .unwrap_or_else(|_| panic!("mac verification failed in test case {}", i,));
    }
}

fn assert_err_with<T>(result: Result<T, TinkError>, needle: &str, msg: &'static str) {
    match result {
        Ok(_) => panic!(msg),
        Err(e) => {
            let detail = format!("{:?}", e);
            assert!(detail.contains(needle), msg);
        }
    }
}

#[test]
fn test_new_hmac_with_invalid_input() {
    tink_mac::init();
    // invalid hash algorithm
    assert_err_with(
        tink_mac::subtle::Hmac::new(HashType::UnknownHash, &get_random_bytes(16), 32),
        "invalid hash algorithm",
        "expect an error when hash algorithm is invalid",
    );

    // key too short
    assert_err_with(
        tink_mac::subtle::Hmac::new(HashType::Sha256, &get_random_bytes(1), 32),
        "key too short",
        "expect an error when key is too short",
    );
    // tag too short
    assert_err_with(
        tink_mac::subtle::Hmac::new(HashType::Sha256, &get_random_bytes(16), 9),
        "tag size too small",
        "expect an error when tag size is too small",
    );
    // tag too big
    assert_err_with(
        tink_mac::subtle::Hmac::new(HashType::Sha1, &get_random_bytes(16), 21),
        "tag size too big",
        "expect an error when tag size is too big",
    );
    assert_err_with(
        tink_mac::subtle::Hmac::new(HashType::Sha256, &get_random_bytes(16), 33),
        "tag size too big",
        "expect an error when tag size is too big",
    );
    assert_err_with(
        tink_mac::subtle::Hmac::new(HashType::Sha512, &get_random_bytes(16), 65),
        "tag size too big",
        "expect an error when tag size is too big",
    );
}

#[test]
fn test_hmac_modification() {
    tink_mac::init();
    for test in HMAC_TESTS {
        let cipher = tink_mac::subtle::Hmac::new(test.hash_alg, test.key, test.tag_size)
            .expect("cannot create new mac");
        let mut mac = cipher
            .compute_mac(test.data)
            .expect("mac computation failed");

        for i in 0..mac.len() {
            let tmp = mac[i];
            for j in 0..8u8 {
                mac[i] ^= 1 << j;
                assert!(
                    cipher.verify_mac(&mac, test.data).is_err(),
                    "test case {}: modified MAC should be invalid",
                    i
                );
                mac[i] = tmp;
            }
        }
    }
}

#[test]
fn test_hmac_truncation() {
    tink_mac::init();
    for test in HMAC_TESTS {
        let cipher = tink_mac::subtle::Hmac::new(test.hash_alg, test.key, test.tag_size)
            .expect("cannot create new mac");
        let mac = cipher
            .compute_mac(test.data)
            .expect("mac computation failed");

        for i in 1..mac.len() {
            assert!(
                cipher.verify_mac(&mac[..i], test.data).is_err(),
                "test case {}: truncated MAC should be invalid",
                i
            );
        }
    }
}
<commit_msg>tink-mac: use expect_err helper in test<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use tink_core::{subtle::random::get_random_bytes, Mac};
use tink_proto::HashType;

struct TestCase {
    hash_alg: HashType,
    tag_size: usize,
    key: &'static [u8],
    data: &'static [u8],
    expected_mac: &'static str,
}

const KEY: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
const DATA: &[u8] = b"Hello";

const HMAC_TESTS : &[TestCase] = &[
    TestCase {
        hash_alg:     HashType::Sha256,
        tag_size:     32,
        data:         DATA,
        key:          KEY,
        expected_mac: "e0ff02553d9a619661026c7aa1ddf59b7b44eac06a9908ff9e19961d481935d4",
    },
    TestCase {
        hash_alg:     HashType::Sha512,
        tag_size:     64,
        data:         DATA,
        key:          KEY,
        expected_mac: "481e10d823ba64c15b94537a3de3f253c16642451ac45124dd4dde120bf1e5c15e55487d55ba72b43039f235226e7954cd5854b30abc4b5b53171a4177047c9b",
    },
    // empty data
    TestCase {
        hash_alg:     HashType::Sha256,
        tag_size:     32,
        data:         &[],
        key:          KEY,
        expected_mac: "07eff8b326b7798c9ccfcbdbe579489ac785a7995a04618b1a2813c26744777d",
    },
];

#[test]
fn test_hmac_basic() {
    tink_mac::init();
    for (i, test) in HMAC_TESTS.iter().enumerate() {
        let cipher = tink_mac::subtle::Hmac::new(test.hash_alg, test.key, test.tag_size)
            .expect("cannot create new mac");
        let mac = cipher
            .compute_mac(test.data)
            .expect("mac computation failed");
        assert_eq!(
            hex::encode(&mac),
            test.expected_mac[..(test.tag_size * 2)],
            "incorrect mac in test case {}",
            i
        );
        cipher
            .verify_mac(&mac, test.data)
            .unwrap_or_else(|_| panic!("mac verification failed in test case {}", i,));
    }
}

#[test]
fn test_new_hmac_with_invalid_input() {
    tink_mac::init();
    // invalid hash algorithm
    tink_tests::expect_err(
        tink_mac::subtle::Hmac::new(HashType::UnknownHash, &get_random_bytes(16), 32),
        "invalid hash algorithm",
    );

    // key too short
    tink_tests::expect_err(
        tink_mac::subtle::Hmac::new(HashType::Sha256, &get_random_bytes(1), 32),
        "key too short",
    );
    // tag too short
    tink_tests::expect_err(
        tink_mac::subtle::Hmac::new(HashType::Sha256, &get_random_bytes(16), 9),
        "tag size too small",
    );
    // tag too big
    tink_tests::expect_err(
        tink_mac::subtle::Hmac::new(HashType::Sha1, &get_random_bytes(16), 21),
        "tag size too big",
    );
    tink_tests::expect_err(
        tink_mac::subtle::Hmac::new(HashType::Sha256, &get_random_bytes(16), 33),
        "tag size too big",
    );
    tink_tests::expect_err(
        tink_mac::subtle::Hmac::new(HashType::Sha512, &get_random_bytes(16), 65),
        "tag size too big",
    );
}

#[test]
fn test_hmac_modification() {
    tink_mac::init();
    for test in HMAC_TESTS {
        let cipher = tink_mac::subtle::Hmac::new(test.hash_alg, test.key, test.tag_size)
            .expect("cannot create new mac");
        let mut mac = cipher
            .compute_mac(test.data)
            .expect("mac computation failed");

        for i in 0..mac.len() {
            let tmp = mac[i];
            for j in 0..8u8 {
                mac[i] ^= 1 << j;
                assert!(
                    cipher.verify_mac(&mac, test.data).is_err(),
                    "test case {}: modified MAC should be invalid",
                    i
                );
                mac[i] = tmp;
            }
        }
    }
}

#[test]
fn test_hmac_truncation() {
    tink_mac::init();
    for test in HMAC_TESTS {
        let cipher = tink_mac::subtle::Hmac::new(test.hash_alg, test.key, test.tag_size)
            .expect("cannot create new mac");
        let mac = cipher
            .compute_mac(test.data)
            .expect("mac computation failed");

        for i in 1..mac.len() {
            assert!(
                cipher.verify_mac(&mac[..i], test.data).is_err(),
                "test case {}: truncated MAC should be invalid",
                i
            );
        }
    }
}
<|endoftext|>