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

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];

const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse",
                                                 "sse2", "sse3", "sse4.1", "sse4.2",
                                                 "ssse3", "tbm", "lzcnt", "popcnt",
                                                 "sse4a", "rdrnd", "rdseed", "fma",
                                                 "xsave", "xsaveopt", "xsavec",
                                                 "xsaves", "aes", "pclmulqdq",
                                                 "avx512bw", "avx512cd",
                                                 "avx512dq", "avx512er",
                                                 "avx512f", "avx512ifma",
                                                 "avx512pf", "avx512vbmi",
                                                 "avx512vl", "avx512vpopcntdq",
                                                 "mmx", "fxsr"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
                                                     "power8-altivec", "power9-altivec",
                                                     "power8-vector", "power9-vector",
                                                     "vsx"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa"];

pub fn to_llvm_feature(s: &str) -> &str {
    match s {
        "pclmulqdq" => "pclmul",
        s => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);
    target_feature_whitelist(sess)
        .iter()
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(feature);
            let ptr = CString::new(llvm_feature).unwrap().as_ptr();
            unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) }
        })
        .map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
    match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    }
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}
<commit_msg>Dangling pointer fix<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];

const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse",
                                                 "sse2", "sse3", "sse4.1", "sse4.2",
                                                 "ssse3", "tbm", "lzcnt", "popcnt",
                                                 "sse4a", "rdrnd", "rdseed", "fma",
                                                 "xsave", "xsaveopt", "xsavec",
                                                 "xsaves", "aes", "pclmulqdq",
                                                 "avx512bw", "avx512cd",
                                                 "avx512dq", "avx512er",
                                                 "avx512f", "avx512ifma",
                                                 "avx512pf", "avx512vbmi",
                                                 "avx512vl", "avx512vpopcntdq",
                                                 "mmx", "fxsr"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
                                                     "power8-altivec", "power9-altivec",
                                                     "power8-vector", "power9-vector",
                                                     "vsx"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa"];

pub fn to_llvm_feature(s: &str) -> &str {
    match s {
        "pclmulqdq" => "pclmul",
        s => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);
    target_feature_whitelist(sess)
        .iter()
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
    match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    }
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}
<|endoftext|>


<commit_before>/*================================================================================================*/
// Copyright 2016 Kyle Finlay
//
// 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.
/*================================================================================================*/

extern crate glob;
extern crate libloading;

use self::glob::glob;
use self::libloading::{Library, Symbol};

use std::vec::Vec;

/*================================================================================================*/
/*------PLUGINTYPE ENUM---------------------------------------------------------------------------*/
/*================================================================================================*/

/// The Plugin Type enum.
#[derive (Copy, Clone, PartialEq, Debug)]
pub enum PluginType {

    /// Used by audio backends.
    AudioBackend,
    /// Used by rendering backends.
    RenderBackend
}

/*================================================================================================*/
/*------PLUGIN STRUCT-----------------------------------------------------------------------------*/
/*================================================================================================*/

/// Stores the details of a plugin.
#[derive (Clone)]
pub struct Plugin {

    // Public
    /// The name of the plugin.
    pub name: String,
    /// The author of the plugin.
    pub author: String,
    /// A brief description of the plugin.
    pub description: String,
    /// The path to the plugin
    pub path: String,
    /// The type of plugin
    pub plugin_type: PluginType,
}

/*================================================================================================*/
/*------PLUGINMANAGER STRUCT----------------------------------------------------------------------*/
/*================================================================================================*/

#[derive (Clone)]
/// Manages the finding and loading of plugins.
pub struct PluginManager {

    // Public
    /// The list of plugins
    pub plugin_list: Vec<Plugin>,
    /// The plugin directory
    pub plugin_dir: String,

    // Private
    _plugin_ext: String
}

/*================================================================================================*/
/*------PLUGINMANAGER PUBLIC MEMBERS--------------------------------------------------------------*/
/*================================================================================================*/

impl PluginManager {

    /// Returns a new plugin manager
    pub fn new (plugin_dir: &str) -> PluginManager {

        // Set the plugin extension
        let mut plug_ext = "";

        // Platform windows
        if cfg! (windows) {
            plug_ext = ".dll";
        }

        // Platform linux
        else if cfg! (linux) {
            plug_ext = ".so";
        }

        PluginManager {plugin_list: Vec::new (),
                       plugin_dir: plugin_dir.to_owned (),
                       _plugin_ext: plug_ext.to_owned ()}
    }

    /// Queries the plugin directory, and stores a list of plugins
    pub fn query_plugins (&mut self) -> &Vec<Plugin> {

        // Clear the old plugin list
        self.plugin_list.clear ();

        // Recurse through all items in the plugin directory
        for path in glob (&format! ("{}/*{}", &self.plugin_dir, &self._plugin_ext)).unwrap ().filter_map (Result::ok) {

            // Load the library, and get function symbols
            let lib = Library::new (&path).unwrap ();

            let get_name: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_name\0").unwrap ()
            };

            let get_author: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_author\0").unwrap ()
            };

            let get_description: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_description\0").unwrap ()
            };

            let get_type: Symbol <unsafe extern fn () -> PluginType> = unsafe {
                lib.get (b"get_type\0").unwrap ()
            };

            unsafe {

                // Add the plugin to the list
                self.plugin_list.push (Plugin {name: get_name (),
                                               author: get_author (),
                                               description: get_description (),
                                               path: path.to_str ().unwrap ().to_owned (),
                                               plugin_type: get_type ()});
            }
        }

        &self.plugin_list
    }
}
<commit_msg>Added OSX lib extension support, and improved extension checking<commit_after>/*================================================================================================*/
// Copyright 2016 Kyle Finlay
//
// 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.
/*================================================================================================*/

extern crate glob;
extern crate libloading;

use self::glob::glob;
use self::libloading::{Library, Symbol};

use std::vec::Vec;

/*================================================================================================*/
/*------PLUGINTYPE ENUM---------------------------------------------------------------------------*/
/*================================================================================================*/

/// The Plugin Type enum.
#[derive (Copy, Clone, PartialEq, Debug)]
pub enum PluginType {

    /// Used by audio backends.
    AudioBackend,
    /// Used by rendering backends.
    RenderBackend
}

/*================================================================================================*/
/*------PLUGIN STRUCT-----------------------------------------------------------------------------*/
/*================================================================================================*/

/// Stores the details of a plugin.
#[derive (Clone)]
pub struct Plugin {

    // Public
    /// The name of the plugin.
    pub name: String,
    /// The author of the plugin.
    pub author: String,
    /// A brief description of the plugin.
    pub description: String,
    /// The path to the plugin
    pub path: String,
    /// The type of plugin
    pub plugin_type: PluginType,
}

/*================================================================================================*/
/*------PLUGINMANAGER STRUCT----------------------------------------------------------------------*/
/*================================================================================================*/

#[derive (Clone)]
/// Manages the finding and loading of plugins.
pub struct PluginManager {

    // Public
    /// The list of plugins
    pub plugin_list: Vec<Plugin>,
    /// The plugin directory
    pub plugin_dir: String,

    // Private
    _plugin_ext: String
}

/*================================================================================================*/
/*------PLUGINMANAGER PUBLIC MEMBERS--------------------------------------------------------------*/
/*================================================================================================*/

impl PluginManager {

    /// Returns a new plugin manager
    pub fn new (plugin_dir: &str) -> PluginManager {

        // Set the platform extension
        let plug_ext = if cfg! (target_os = "windows") {".dll"}
                       else if cfg! (target_os = "linux") {".so"}
                       else if cfg! (target_os = "macos") {".dylib"}
                       else {panic! ("Platform unsupported")};

        PluginManager {plugin_list: Vec::new (),
                       plugin_dir: plugin_dir.to_owned (),
                       _plugin_ext: plug_ext.to_owned ()}
    }

    /// Queries the plugin directory, and stores a list of plugins
    pub fn query_plugins (&mut self) -> &Vec<Plugin> {

        // Clear the old plugin list
        self.plugin_list.clear ();

        // Recurse through all items in the plugin directory
        for path in glob (&format! ("{}/*{}", &self.plugin_dir, &self._plugin_ext)).unwrap ().filter_map (Result::ok) {

            // Load the library, and get function symbols
            let lib = Library::new (&path).unwrap ();

            let get_name: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_name\0").unwrap ()
            };

            let get_author: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_author\0").unwrap ()
            };

            let get_description: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_description\0").unwrap ()
            };

            let get_type: Symbol <unsafe extern fn () -> PluginType> = unsafe {
                lib.get (b"get_type\0").unwrap ()
            };

            unsafe {

                // Add the plugin to the list
                self.plugin_list.push (Plugin {name: get_name (),
                                               author: get_author (),
                                               description: get_description (),
                                               path: path.to_str ().unwrap ().to_owned (),
                                               plugin_type: get_type ()});
            }
        }

        &self.plugin_list
    }
}
<|endoftext|>


<commit_before>//! Extended attribute support for Darwin and Linux systems.
extern crate libc;

use std::io;
use std::path::Path;
use std::ffi::CString;

pub const ENABLED: bool = cfg!(feature="git") && cfg!(any(target_os="macos", target_os="linux"));

pub trait FileAttributes {
    fn attributes(&self) -> io::Result<Vec<Attribute>>;
    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>>;
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::Yes), &self)
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::No), &self)
    }
}

#[cfg(not(any(target_os = "macos", target_os = "linux")))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }
}

/// Attributes which can be passed to `Attribute::list_with_flags`
#[cfg(any(target_os = "macos", target_os = "linux"))]
#[derive(Copy, Clone)]
pub enum FollowSymlinks {
    Yes,
    No
}

/// Extended attribute
#[derive(Debug, Clone)]
pub struct Attribute {
    pub name: String,
    pub size: usize,
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
    let c_path = match path.to_str().and_then(|s| { CString::new(s).ok() }) {
        Some(cstring) => cstring,
        None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")),
    };

    let mut names = Vec::new();
    let bufsize = lister.listxattr_first(&c_path);

    if bufsize < 0 {
        return Err(io::Error::last_os_error());
    }
    else if bufsize > 0 {
        let mut buf = vec![0u8; bufsize as usize];
        let err = lister.listxattr_second(&c_path, &mut buf, bufsize);

        if err < 0 {
            return Err(io::Error::last_os_error());
        }

        if err > 0 {
            // End indicies of the attribute names
            // the buffer contains 0-terminates c-strings
            let idx = buf.iter().enumerate().filter_map(|(i, v)|
                if *v == 0 { Some(i) } else { None }
            );
            let mut start = 0;

            for end in idx {
                let c_end = end + 1; // end of the c-string (including 0)
                let size = lister.getxattr(&c_path, &buf[start..c_end]);

                if size > 0 {
                    names.push(Attribute {
                        name: lister.translate_attribute_name(&buf[start..end]),
                        size: size as usize
                    });
                }

                start = c_end;
            }

        }

    }
    Ok(names)
}

#[cfg(target_os = "macos")]
mod lister {
    use std::ffi::CString;
    use libc::{c_int, size_t, ssize_t, c_char, c_void, uint32_t};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, namebuf: *mut c_char,
            size: size_t, options: c_int
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t, position: uint32_t,
            options: c_int
        ) -> ssize_t;
    }

    pub struct Lister {
        c_flags: c_int,
    }

    impl Lister {
        pub fn new(do_follow: FollowSymlinks) -> Lister {
            let c_flags: c_int = match do_follow {
                FollowSymlinks::Yes => 0x0001,
                FollowSymlinks::No  => 0x0000,
            };

            Lister { c_flags: c_flags }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            use std::str::from_utf8_unchecked;

            unsafe {
                from_utf8_unchecked(input).into()
            }
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0, self.c_flags)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t, self.c_flags
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0, 0, self.c_flags
                )
            }
        }
    }
}

#[cfg(target_os = "linux")]
mod lister {
    use std::ffi::CString;
    use libc::{size_t, ssize_t, c_char, c_void};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn llistxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;

        fn lgetxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;
    }

    pub struct Lister {
        follow_symlinks: FollowSymlinks,
    }

    impl Lister {
        pub fn new(follow_symlinks: FollowSymlinks) -> Lister {
            Lister { follow_symlinks: follow_symlinks }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            String::from_utf8_lossy(input).into_owned()
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            let getxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => getxattr,
                FollowSymlinks::No  => lgetxattr,
            };

            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0
                )
            }
        }
    }
}
<commit_msg>Move CString to where it's actually used<commit_after>//! Extended attribute support for Darwin and Linux systems.
extern crate libc;

use std::io;
use std::path::Path;

pub const ENABLED: bool = cfg!(feature="git") && cfg!(any(target_os="macos", target_os="linux"));

pub trait FileAttributes {
    fn attributes(&self) -> io::Result<Vec<Attribute>>;
    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>>;
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::Yes), &self)
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::No), &self)
    }
}

#[cfg(not(any(target_os = "macos", target_os = "linux")))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }
}

/// Attributes which can be passed to `Attribute::list_with_flags`
#[cfg(any(target_os = "macos", target_os = "linux"))]
#[derive(Copy, Clone)]
pub enum FollowSymlinks {
    Yes,
    No
}

/// Extended attribute
#[derive(Debug, Clone)]
pub struct Attribute {
    pub name: String,
    pub size: usize,
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
    use std::ffi::CString;

    let c_path = match path.to_str().and_then(|s| { CString::new(s).ok() }) {
        Some(cstring) => cstring,
        None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")),
    };

    let mut names = Vec::new();
    let bufsize = lister.listxattr_first(&c_path);

    if bufsize < 0 {
        return Err(io::Error::last_os_error());
    }
    else if bufsize > 0 {
        let mut buf = vec![0u8; bufsize as usize];
        let err = lister.listxattr_second(&c_path, &mut buf, bufsize);

        if err < 0 {
            return Err(io::Error::last_os_error());
        }

        if err > 0 {
            // End indicies of the attribute names
            // the buffer contains 0-terminates c-strings
            let idx = buf.iter().enumerate().filter_map(|(i, v)|
                if *v == 0 { Some(i) } else { None }
            );
            let mut start = 0;

            for end in idx {
                let c_end = end + 1; // end of the c-string (including 0)
                let size = lister.getxattr(&c_path, &buf[start..c_end]);

                if size > 0 {
                    names.push(Attribute {
                        name: lister.translate_attribute_name(&buf[start..end]),
                        size: size as usize
                    });
                }

                start = c_end;
            }

        }

    }
    Ok(names)
}

#[cfg(target_os = "macos")]
mod lister {
    use std::ffi::CString;
    use libc::{c_int, size_t, ssize_t, c_char, c_void, uint32_t};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, namebuf: *mut c_char,
            size: size_t, options: c_int
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t, position: uint32_t,
            options: c_int
        ) -> ssize_t;
    }

    pub struct Lister {
        c_flags: c_int,
    }

    impl Lister {
        pub fn new(do_follow: FollowSymlinks) -> Lister {
            let c_flags: c_int = match do_follow {
                FollowSymlinks::Yes => 0x0001,
                FollowSymlinks::No  => 0x0000,
            };

            Lister { c_flags: c_flags }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            use std::str::from_utf8_unchecked;

            unsafe {
                from_utf8_unchecked(input).into()
            }
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0, self.c_flags)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t, self.c_flags
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0, 0, self.c_flags
                )
            }
        }
    }
}

#[cfg(target_os = "linux")]
mod lister {
    use std::ffi::CString;
    use libc::{size_t, ssize_t, c_char, c_void};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn llistxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;

        fn lgetxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;
    }

    pub struct Lister {
        follow_symlinks: FollowSymlinks,
    }

    impl Lister {
        pub fn new(follow_symlinks: FollowSymlinks) -> Lister {
            Lister { follow_symlinks: follow_symlinks }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            String::from_utf8_lossy(input).into_owned()
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            let getxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => getxattr,
                FollowSymlinks::No  => lgetxattr,
            };

            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0
                )
            }
        }
    }
}
<|endoftext|>


<commit_before>
extern mod cortex;

use cortex::regs::{store, set, wait_for};
use sim::{enable_clock, USBOTG};
use sim::{select_usb_source};

mod sim;

static BASE_USB: u32        = 0x4007_2000;
static USB_USBTRC0: u32     = BASE_USB + 0x010C;
static USB_USBCTRL: u32     = BASE_USB + 0x0100;
static USB_CTL: u32         = BASE_USB + 0x0094;
static USB_ADDR: u32        = BASE_USB + 0x0098;
static USB_CONTROL: u32     = BASE_USB + 0x0108;

static USB_ISTAT: u32       = BASE_USB + 0x0080;
static USB_ERRSTAT: u32     = BASE_USB + 0x0088;
static USB_OTGISTAT: u32    = BASE_USB + 0x0010;

static USB_BDTPAGE1: u32    = BASE_USB + 0x009C;
static USB_BDTPAGE2: u32    = BASE_USB + 0x00B0;
static USB_BDTPAGE3: u32    = BASE_USB + 0x00B4;

fn zero_bdt() {
}

fn set_bdt() {
    // Need a 512 byte aligned memory
    let addr: u32 = 0x00; // This should be a pointer to the BDT
    unsafe {
        store(USB_BDTPAGE1 as *mut u8, (addr << 8) as u8);
        store(USB_BDTPAGE2 as *mut u8, (addr << 16) as u8);
        store(USB_BDTPAGE3 as *mut u8, (addr << 24) as u8);
    }
}

fn usb_reset_hard() {
    unsafe {
        let addr: *mut u8 = (BASE_USB + 0x010C) as *mut u8;
        store(addr, 0x80);
        wait_for(addr as *u8, 0x808, 0x00);
    }
}

pub fn usb_address(addr: u8) {
    unsafe {
        store(USB_ADDR as *mut u8, addr);
    }
}

pub fn usb_reset(on_before_enable: ||) {
    unsafe {
        // Disable and suspend USB module
        set(USB_CTL as *mut u8, 0x22);

        // Clear any remaining status flags
        store(USB_ISTAT as *mut u8, 0x00);
        store(USB_ERRSTAT as *mut u8, 0x00);
        store(USB_OTGISTAT as *mut u8, 0x00);

        // Zero out BDT
        zero_bdt();

        // Reset address
        usb_address(0x00);

        // Call supplied function (should initialise EP0)
        on_before_enable();

        // Enable USB module
        store(USB_CTL as *mut u8, 0x01);
    }
}

pub fn usb_init(on_before_enable: ||) {
    // Enable the SIM clock for USB
    enable_clock(USBOTG);

    // Set the USB clock source to internal
    select_usb_source(true);

    // Cycle the USB module through a hard reset
    usb_reset_hard();

    // Load the address of the BDT
    set_bdt();

    // Enable the DP pullup
    unsafe { set(USB_CONTROL as *mut u8, 0x10); }

    // Enable the transceiver and disable pulldowns
    unsafe { store(USB_USBCTRL as *mut u8, 0x00); }

    // Run the software USB reset
    usb_reset(on_before_enable);

    // Enable interrupts for USBRST, TOKDNE and STALL
    set_interrupts(0x89);
}
<commit_msg>Neatened USB a bit<commit_after>
extern mod cortex;

use cortex::regs::{store, set, wait_for};
use sim::{enable_clock, USBOTG};
use sim::{select_usb_source};

mod sim;

static BASE_USB: u32        = 0x4007_2000;
static USB_USBTRC0: u32     = BASE_USB + 0x010C;
static USB_USBCTRL: u32     = BASE_USB + 0x0100;
static USB_CTL: u32         = BASE_USB + 0x0094;
static USB_ADDR: u32        = BASE_USB + 0x0098;
static USB_CONTROL: u32     = BASE_USB + 0x0108;
static USB_INTEN: u32       = BASE_USB + 0x0084;

static USB_ISTAT: u32       = BASE_USB + 0x0080;
static USB_ERRSTAT: u32     = BASE_USB + 0x0088;
static USB_OTGISTAT: u32    = BASE_USB + 0x0010;

static USB_BDTPAGE1: u32    = BASE_USB + 0x009C;
static USB_BDTPAGE2: u32    = BASE_USB + 0x00B0;
static USB_BDTPAGE3: u32    = BASE_USB + 0x00B4;

pub enum Usb_Int {
    USBRSTEN = 0x01,
    ERROREN  = 0x02,
    SOFTOKEN = 0x04,
    TOKDNEEN = 0x08,
    SLEEPEN  = 0x10,
    RESUMEEN = 0x20,
    ATTACHEN = 0x40,
    STALLEN  = 0x80
}

fn zero_bdt() {
}

fn set_bdt() {
    // Need a 512 byte aligned memory
    let addr: u32 = 0x00; // This should be a pointer to the BDT
    unsafe {
        store(USB_BDTPAGE1 as *mut u8, (addr << 8) as u8);
        store(USB_BDTPAGE2 as *mut u8, (addr << 16) as u8);
        store(USB_BDTPAGE3 as *mut u8, (addr << 24) as u8);
    }
}

fn usb_reset_hard() {
    unsafe {
        let addr: *mut u8 = (BASE_USB + 0x010C) as *mut u8;
        store(addr, 0x80);
        wait_for(addr as *u8, 0x808, 0x00);
    }
}

pub fn set_interrupt(val: Usb_Int) {
    unsafe {
        set(USB_INTEN as *mut u8, val as u8);
    }
}

pub fn set_interrupts(val: u8) {
    unsafe {
        store(USB_INTEN as *mut u8, val as u8);
    }
}

pub fn usb_address(addr: u8) {
    unsafe {
        store(USB_ADDR as *mut u8, addr);
    }
}

pub fn usb_reset(on_before_enable: ||) {
    unsafe {
        // Disable and suspend USB module
        set(USB_CTL as *mut u8, 0x22);

        // Clear any remaining status flags
        store(USB_ISTAT as *mut u8, 0xFF);
        store(USB_ERRSTAT as *mut u8, 0xFF);
        store(USB_OTGISTAT as *mut u8, 0xFF);

        // Zero out BDT
        zero_bdt();

        // Reset address
        usb_address(0x00);

        // Call supplied function (should initialise EP0)
        on_before_enable();

        // Enable USB module
        store(USB_CTL as *mut u8, 0x01);
    }
}

pub fn usb_init(on_before_enable: ||) {
    // Enable the SIM clock for USB
    enable_clock(USBOTG);

    // Set the USB clock source to internal
    select_usb_source(true);

    // Cycle the USB module through a hard reset
    usb_reset_hard();

    // Load the address of the BDT
    set_bdt();

    // Enable the DP pullup
    unsafe { set(USB_CONTROL as *mut u8, 0x10); }

    // Enable the transceiver and disable pulldowns
    unsafe { store(USB_USBCTRL as *mut u8, 0x00); }

    // Run the software USB reset
    usb_reset(on_before_enable);

    // Enable interrupts for USBRST, TOKDNE and STALL
    set_interrupts(STALLEN as u8 |
                  TOKDNEEN as u8 |
                  USBRSTEN as u8);
}
<|endoftext|>


<commit_before>use crate::value;
use chrono;
use combine::char::{char, digit};
use combine::combinator::{skip_count_min_max, SkipCountMinMax};
use combine::range::{recognize, recognize_with_value};
use combine::stream::RangeStream;
use combine::*;

#[inline]
pub fn repeat<P: Parser>(count: usize, parser: P) -> SkipCountMinMax<P> {
    skip_count_min_max(count, count, parser)
}

// ;; Date and Time (as defined in RFC 3339)

// date-time = offset-date-time / local-date-time / local-date / local-time
// offset-date-time = full-date "T" full-time
// local-date-time = full-date "T" partial-time
// local-date = full-date
// local-time = partial-time
// full-time = partial-time time-offset
parse!(date_time() -> value::DateTime, {
    choice!(
        recognize_with_value((
            full_date(),
            optional((
                char('T'),
                partial_time(),
                optional(time_offset()),
            ))
        ))
            .and_then(|(s, (_, opt))| {
                match opt {
                    // Offset Date-Time
                    Some((_, _, Some(_))) => {
                        chrono::DateTime::parse_from_rfc3339(s)
                            .map(value::DateTime::OffsetDateTime)
                    }
                    // Local Date-Time
                    Some(_) => {
                        s.parse::<chrono::NaiveDateTime>()
                            .map(value::DateTime::LocalDateTime)
                    }
                    // Local Date
                    None => {
                        s.parse::<chrono::NaiveDate>()
                            .map(value::DateTime::LocalDate)
                    }
                }

            }),
        // Local Time
        recognize(partial_time())
            .and_then(str::parse)
            .message("While parsing a Time")
            .map(value::DateTime::LocalTime)
    )
        .message("While parsing a Date-Time")
});

// full-date      = date-fullyear "-" date-month "-" date-mday
// date-fullyear  = 4DIGIT
// date-month     = 2DIGIT  ; 01-12
// date-mday      = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
parse!(full_date() -> &'a str, {
    recognize((
        attempt((repeat(4, digit()), char('-'))),
        repeat(2, digit()),
        char('-'),
        repeat(2, digit()),
    ))
});

// partial-time   = time-hour ":" time-minute ":" time-second [time-secfrac]
// time-hour      = 2DIGIT  ; 00-23
// time-minute    = 2DIGIT  ; 00-59
// time-second    = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
// time-secfrac   = "." 1*DIGIT
parse!(partial_time() -> (), {
    (
        attempt((
            repeat(2, digit()),
            char(':'),
        )),
        repeat(2, digit()),
        char(':'),
        repeat(2, digit()),
        optional(attempt(char('.')).and(skip_many1(digit()))),
    ).map(|_| ())
});

// time-offset    = "Z" / time-numoffset
// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
parse!(time_offset() -> (), {
    attempt(char('Z')).map(|_| ())
        .or(
            (
                attempt(choice([char('+'), char('-')])),
                repeat(2, digit()),
                char(':'),
                repeat(2, digit()),
            ).map(|_| ())
        ).message("While parsing a Time Offset")
});
<commit_msg>obey clippy<commit_after>use crate::value;
use combine::char::{char, digit};
use combine::combinator::{skip_count_min_max, SkipCountMinMax};
use combine::range::{recognize, recognize_with_value};
use combine::stream::RangeStream;
use combine::*;

#[inline]
pub fn repeat<P: Parser>(count: usize, parser: P) -> SkipCountMinMax<P> {
    skip_count_min_max(count, count, parser)
}

// ;; Date and Time (as defined in RFC 3339)

// date-time = offset-date-time / local-date-time / local-date / local-time
// offset-date-time = full-date "T" full-time
// local-date-time = full-date "T" partial-time
// local-date = full-date
// local-time = partial-time
// full-time = partial-time time-offset
parse!(date_time() -> value::DateTime, {
    choice!(
        recognize_with_value((
            full_date(),
            optional((
                char('T'),
                partial_time(),
                optional(time_offset()),
            ))
        ))
            .and_then(|(s, (_, opt))| {
                match opt {
                    // Offset Date-Time
                    Some((_, _, Some(_))) => {
                        chrono::DateTime::parse_from_rfc3339(s)
                            .map(value::DateTime::OffsetDateTime)
                    }
                    // Local Date-Time
                    Some(_) => {
                        s.parse::<chrono::NaiveDateTime>()
                            .map(value::DateTime::LocalDateTime)
                    }
                    // Local Date
                    None => {
                        s.parse::<chrono::NaiveDate>()
                            .map(value::DateTime::LocalDate)
                    }
                }

            }),
        // Local Time
        recognize(partial_time())
            .and_then(str::parse)
            .message("While parsing a Time")
            .map(value::DateTime::LocalTime)
    )
        .message("While parsing a Date-Time")
});

// full-date      = date-fullyear "-" date-month "-" date-mday
// date-fullyear  = 4DIGIT
// date-month     = 2DIGIT  ; 01-12
// date-mday      = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
parse!(full_date() -> &'a str, {
    recognize((
        attempt((repeat(4, digit()), char('-'))),
        repeat(2, digit()),
        char('-'),
        repeat(2, digit()),
    ))
});

// partial-time   = time-hour ":" time-minute ":" time-second [time-secfrac]
// time-hour      = 2DIGIT  ; 00-23
// time-minute    = 2DIGIT  ; 00-59
// time-second    = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
// time-secfrac   = "." 1*DIGIT
parse!(partial_time() -> (), {
    (
        attempt((
            repeat(2, digit()),
            char(':'),
        )),
        repeat(2, digit()),
        char(':'),
        repeat(2, digit()),
        optional(attempt(char('.')).and(skip_many1(digit()))),
    ).map(|_| ())
});

// time-offset    = "Z" / time-numoffset
// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
parse!(time_offset() -> (), {
    attempt(char('Z')).map(|_| ())
        .or(
            (
                attempt(choice([char('+'), char('-')])),
                repeat(2, digit()),
                char(':'),
                repeat(2, digit()),
            ).map(|_| ())
        ).message("While parsing a Time Offset")
});
<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;
use gl;
use gl::types::GLint;

use graphics::{
    AddColor,
    Clear,
    Context,
    ColorContext,
    RelativeTransform2d,
    View,
};
use {
    AssetStore,
    GameWindow,
    Gl,
    GlData,
};
use keyboard;
use mouse;
use event;

/// Render argument.
pub struct RenderArgs<'a> {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// Rust-Graphics context.
    pub context: Context<'a>,
    /// OpenGL back-end for Rust-Graphics.
    pub gl: Gl<'a>,
}

/// Update argument.
pub struct UpdateArgs<'a> {
    /// Delta time in seconds.
    pub dt: f64,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Load arguments.
pub struct LoadArgs<'a> {
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Key press arguments.
pub struct KeyPressArgs<'a> {
    /// Keyboard key.
    pub key: keyboard::Key,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Key release arguments.
pub struct KeyReleaseArgs<'a> {
    /// Keyboard key.
    pub key: keyboard::Key,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse press arguments.
pub struct MousePressArgs<'a> {
    /// Mouse button.
    pub button: mouse::Button,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse release arguments.
pub struct MouseReleaseArgs<'a> {
    /// Mouse button.
    pub button: mouse::Button,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse move arguments.
pub struct MouseMoveArgs<'a> {
    /// y.
    pub x: f64,
    /// x.
    pub y: f64,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse relative move arguments.
pub struct MouseRelativeMoveArgs<'a> {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Contains the different game events.
pub enum GameEvent<'a> {
    /// Render graphics.
    Render(RenderArgs<'a>),
    /// Update physical state of the game.
    Update(UpdateArgs<'a>),
    /// Performs tasks for loading before showing anything.
    Load(LoadArgs<'a>),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs<'a>),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs<'a>),
    /// Pressed a mouse button.
    MousePress(MousePressArgs<'a>),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs<'a>),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs<'a>),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs<'a>),
}

enum GameIteratorState {
    LoadState,
    RenderState,
    SwapBuffersState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// A game loop iterator.
pub struct GameIterator<'a, W> {
    game_window: &'a mut W,
    asset_store: &'a mut AssetStore,
    state: GameIteratorState,
    gl_data: GlData,
    context: Context<'a>,
    bg: ColorContext<'a>,
    last_update: u64,
    update_time_in_ns: u64,
    dt: f64,
    min_updates_per_frame: u64,
    min_ns_per_frame: u64,
    start_render: u64,
    updated: u64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(game_window: &'a mut W, asset_store: &'a mut AssetStore) -> GameIterator<'a, W> {
        let bg = game_window.get_settings().background_color;
        let context = Context::new();
        let bg = context.color(bg);
        let updates_per_second: u64 = 120;
        let max_frames_per_second: u64 = 60;
        // You can make this lower if needed
        let min_updates_per_frame: u64 = updates_per_second / max_frames_per_second;
        let dt: f64 = 1.0 / updates_per_second as f64;
        let update_time_in_ns: u64 = billion / updates_per_second;

        let start = time::precise_time_ns();
        let min_ns_per_frame = billion / max_frames_per_second;
        let last_update = start;
        GameIterator {
            game_window: game_window,
            asset_store: asset_store,
            state: LoadState,
            gl_data: GlData::new(),
            context: context,
            last_update: last_update,
            update_time_in_ns: update_time_in_ns,
            dt: dt,
            min_updates_per_frame: min_updates_per_frame,
            min_ns_per_frame: min_ns_per_frame,
            start_render: start,
            bg: bg.clone(),
            updated: 0,
        }
    }

    /// Returns the next game event.
    pub fn next<'a>(&'a mut self) -> Option<GameEvent<'a>> {
        if self.game_window.should_close() { return None; }

        match self.state {
            LoadState => {
                self.state = RenderState;
                return Some(Load(LoadArgs {
                    asset_store: self.asset_store
                }));
            },
            RenderState => {
                let start_render = time::precise_time_ns();
                // Rendering code
                let (w, h) = self.game_window.get_size();
                if w != 0 && h != 0 {
                    // Swap buffers next time.
                    self.state = SwapBuffersState;
                    gl::Viewport(0, 0, w as GLint, h as GLint);
                    // self.viewport(self.game_window);
                    let mut gl = Gl::new(&mut self.gl_data, self.asset_store);
                    self.bg.clear(&mut gl);
                    // Extrapolate time forward to allow smooth motion.
                    // 'now' is always bigger than 'last_update'.
                    let ext_dt = (start_render - self.last_update) as f64 / billion as f64;
                    return Some(Render(RenderArgs {
                        ext_dt: ext_dt,
                        context: self.context
                            .trans(-1.0, 1.0)
                            .scale(2.0 / w as f64, -2.0 / h as f64)
                            .store_view().clone(),
                        gl: gl
                    }));
                }

                // Jump to next state.
                // Reset update counter.
                self.updated = 0;
                self.state = UpdateState;
                return self.next();
            },
            SwapBuffersState => {
                self.game_window.swap_buffers();
                // Reset update counter.
                self.updated = 0;
                self.state = UpdateState;
                return self.next();
            },
            HandleEventsState => {
                let next_render = self.start_render + self.min_ns_per_frame;

                if // If we haven't reached the required number of updates yet
                  ( self.updated < self.min_updates_per_frame
                  // Or we have the time to update further
                  || time::precise_time_ns() < next_render )
                  // And we haven't already progressed time to far
                  && self.last_update + self.update_time_in_ns < next_render {

                    self.last_update += self.update_time_in_ns;

                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                                asset_store: self.asset_store,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                                asset_store: self.asset_store,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                                asset_store: self.asset_store,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                                asset_store: self.asset_store,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                                asset_store: self.asset_store,
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            self.next()
                        },
                    }
                }

                // Wait if possible
                let t = (next_render - time::precise_time_ns() ) / 1_000_000;
                if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                          // which tells us that t should have been negative
                                          // and we are running slow and shouldn't sleep.
                    sleep( t );
                }
                self.state = RenderState;
                return self.next();
            },
            MouseRelativeMoveState(dx, dy) => {
                self.state = HandleEventsState;
                return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                    dx: dx,
                    dy: dy,
                    asset_store: self.asset_store,
                }));
            },
            UpdateState => {
                self.updated += 1;
                self.state = HandleEventsState;
                return Some(Update(UpdateArgs{
                    dt: self.dt,
                    asset_store: self.asset_store
                }));
            },
        };

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}

<commit_msg>Fixed bug in iterator<commit_after>use time;
use std::io::timer::sleep;
use gl;
use gl::types::GLint;

use graphics::{
    AddColor,
    Clear,
    Context,
    ColorContext,
    RelativeTransform2d,
    View,
};
use {
    AssetStore,
    GameWindow,
    Gl,
    GlData,
};
use keyboard;
use mouse;
use event;

/// Render argument.
pub struct RenderArgs<'a> {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// Rust-Graphics context.
    pub context: Context<'a>,
    /// OpenGL back-end for Rust-Graphics.
    pub gl: Gl<'a>,
}

/// Update argument.
pub struct UpdateArgs<'a> {
    /// Delta time in seconds.
    pub dt: f64,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Load arguments.
pub struct LoadArgs<'a> {
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Key press arguments.
pub struct KeyPressArgs<'a> {
    /// Keyboard key.
    pub key: keyboard::Key,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Key release arguments.
pub struct KeyReleaseArgs<'a> {
    /// Keyboard key.
    pub key: keyboard::Key,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse press arguments.
pub struct MousePressArgs<'a> {
    /// Mouse button.
    pub button: mouse::Button,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse release arguments.
pub struct MouseReleaseArgs<'a> {
    /// Mouse button.
    pub button: mouse::Button,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse move arguments.
pub struct MouseMoveArgs<'a> {
    /// y.
    pub x: f64,
    /// x.
    pub y: f64,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Mouse relative move arguments.
pub struct MouseRelativeMoveArgs<'a> {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
    /// Asset store.
    pub asset_store: &'a mut AssetStore,
}

/// Contains the different game events.
pub enum GameEvent<'a> {
    /// Render graphics.
    Render(RenderArgs<'a>),
    /// Update physical state of the game.
    Update(UpdateArgs<'a>),
    /// Performs tasks for loading before showing anything.
    Load(LoadArgs<'a>),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs<'a>),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs<'a>),
    /// Pressed a mouse button.
    MousePress(MousePressArgs<'a>),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs<'a>),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs<'a>),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs<'a>),
}

enum GameIteratorState {
    LoadState,
    RenderState,
    SwapBuffersState,
    PrepareUpdateLoopState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// A game loop iterator.
pub struct GameIterator<'a, W> {
    game_window: &'a mut W,
    asset_store: &'a mut AssetStore,
    state: GameIteratorState,
    gl_data: GlData,
    context: Context<'a>,
    bg: ColorContext<'a>,
    last_update: u64,
    update_time_in_ns: u64,
    dt: f64,
    min_updates_per_frame: u64,
    min_ns_per_frame: u64,
    start_render: u64,
    next_render: u64,
    updated: u64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(game_window: &'a mut W, asset_store: &'a mut AssetStore) -> GameIterator<'a, W> {
        let bg = game_window.get_settings().background_color;
        let context = Context::new();
        let bg = context.color(bg);
        let updates_per_second: u64 = 120;
        let max_frames_per_second: u64 = 60;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            asset_store: asset_store,
            state: LoadState,
            gl_data: GlData::new(),
            context: context,
            last_update: start,
            update_time_in_ns: billion / updates_per_second,
            dt: 1.0 / updates_per_second as f64,
            // You can make this lower if needed.
            min_updates_per_frame: updates_per_second / max_frames_per_second,
            min_ns_per_frame: billion / max_frames_per_second,
            start_render: start,
            next_render: start,
            bg: bg.clone(),
            updated: 0,
        }
    }

    /// Returns the next game event.
    pub fn next<'a>(&'a mut self) -> Option<GameEvent<'a>> {
        match self.state {
            LoadState => {
                self.state = RenderState;
                return Some(Load(LoadArgs {
                    asset_store: self.asset_store
                }));
            },
            RenderState => {
                if self.game_window.should_close() { return None; }

                self.start_render = time::precise_time_ns();
                // Rendering code
                let (w, h) = self.game_window.get_size();
                if w != 0 && h != 0 {
                    gl::Viewport(0, 0, w as GLint, h as GLint);
                    // self.viewport(self.game_window);
                    let mut gl = Gl::new(&mut self.gl_data, self.asset_store);
                    self.bg.clear(&mut gl);
                    // Swap buffers next time.
                    self.state = SwapBuffersState;
                    return Some(Render(RenderArgs {
                        // Extrapolate time forward to allow smooth motion.
                        // 'start_render' is always bigger than 'last_update'.
                        ext_dt: (self.start_render - self.last_update) as f64 / billion as f64,
                        context: self.context
                            .trans(-1.0, 1.0)
                            .scale(2.0 / w as f64, -2.0 / h as f64)
                            .store_view().clone(),
                        gl: gl
                    }));
                }

                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            SwapBuffersState => {
                self.game_window.swap_buffers();
                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            PrepareUpdateLoopState => {
                self.updated = 0;
                self.next_render = self.start_render + self.min_ns_per_frame;
                self.state = UpdateLoopState;
                return self.next();
            },
            UpdateLoopState => {
                let got_min_updates = self.updated < self.min_updates_per_frame;
                let got_time_to_update = time::precise_time_ns() < self.next_render;
                let before_next_frame = self.last_update + self.update_time_in_ns < self.next_render;

                if ( got_time_to_update || got_min_updates ) && before_next_frame {
                    self.state = HandleEventsState;
                    return self.next();
                }

                // Wait if possible.
                // Convert to ms because that is what the sleep function takes.
                let t = (self.next_render - time::precise_time_ns() ) / 1_000_000;
                if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                          // which tells us that t should have been negative
                                          // and we are running slow and shouldn't sleep.
                    sleep( t );
                }
                self.state = RenderState;
                return self.next();
            },
            HandleEventsState => {
                // Handle all events before updating.
                return match self.game_window.poll_event() {
                    event::KeyPressed(key) => {
                        Some(KeyPress(KeyPressArgs {
                            key: key,
                            asset_store: self.asset_store,
                        }))
                    },
                    event::KeyReleased(key) => {
                        Some(KeyRelease(KeyReleaseArgs {
                            key: key,
                            asset_store: self.asset_store,
                        }))
                    },
                    event::MouseButtonPressed(mouse_button) => {
                        Some(MousePress(MousePressArgs {
                            button: mouse_button,
                            asset_store: self.asset_store,
                        }))
                    },
                    event::MouseButtonReleased(mouse_button) => {
                        Some(MouseRelease(MouseReleaseArgs {
                            button: mouse_button,
                            asset_store: self.asset_store,
                        }))
                    },
                    event::MouseMoved(x, y, relative_move) => {
                        match relative_move {
                            Some((dx, dy)) =>
                                self.state = MouseRelativeMoveState(dx, dy),
                            None => {},
                        };
                        Some(MouseMove(MouseMoveArgs {
                            x: x,
                            y: y,
                            asset_store: self.asset_store,
                        }))
                    },
                    event::NoEvent => {
                        self.state = UpdateState;
                        self.next()
                    },
                }
            },
            MouseRelativeMoveState(dx, dy) => {
                self.state = HandleEventsState;
                return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                    dx: dx,
                    dy: dy,
                    asset_store: self.asset_store,
                }));
            },
            UpdateState => {
                self.updated += 1;
                self.state = UpdateLoopState;
                self.last_update += self.update_time_in_ns;
                return Some(Update(UpdateArgs{
                    dt: self.dt,
                    asset_store: self.asset_store
                }));
            },
        };

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}

<|endoftext|>


<commit_before>use crate::{
    hotkey::{Hook, KeyCode},
    HotkeyConfig, SharedTimer,
};

pub use crate::hotkey::{Error, Result};

// This enum might be better situated in hotkey_config, but the last method should stay in this file
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Hotkey {
    Split,
    /// The key to use for resetting the current attempt.
    Reset,
    /// The key to use for undoing the last split.
    Undo,
    /// The key to use for skipping the current split.
    Skip,
    /// The key to use for pausing the current attempt and starting a new
    /// attempt.
    Pause,
    /// The key to use for removing all the pause times from the current time.
    UndoAllPauses,
    /// The key to use for switching to the previous comparison.
    PreviousComparison,
    /// The key to use for switching to the next comparison.
    NextComparison,
    /// The key to use for toggling between the `Real Time` and `Game Time`
    /// timing methods.
    ToggleTimingMethod,
}

impl Hotkey {
    fn set_keycode(self, config: &mut HotkeyConfig, keycode: Option<KeyCode>) {
        match self {
            Hotkey::Split => config.split = keycode,
            Hotkey::Reset => config.reset = keycode,
            Hotkey::Undo => config.undo = keycode,
            Hotkey::Skip => config.skip = keycode,
            Hotkey::Pause => config.pause = keycode,
            Hotkey::UndoAllPauses => config.undo_all_pauses = keycode,
            Hotkey::PreviousComparison => config.previous_comparison = keycode,
            Hotkey::NextComparison => config.next_comparison = keycode,
            Hotkey::ToggleTimingMethod => config.toggle_timing_method = keycode,
        }
    }

    const fn get_keycode(self, config: &HotkeyConfig) -> Option<KeyCode> {
        match self {
            Hotkey::Split => config.split,
            Hotkey::Reset => config.reset,
            Hotkey::Undo => config.undo,
            Hotkey::Skip => config.skip,
            Hotkey::Pause => config.pause,
            Hotkey::UndoAllPauses => config.undo_all_pauses,
            Hotkey::PreviousComparison => config.previous_comparison,
            Hotkey::NextComparison => config.next_comparison,
            Hotkey::ToggleTimingMethod => config.toggle_timing_method,
        }
    }

    fn callback(self, timer: SharedTimer) -> Box<dyn FnMut() + Send + 'static> {
        match self {
            Hotkey::Split => Box::new(move || timer.write().split_or_start()),
            Hotkey::Reset => Box::new(move || timer.write().reset(true)),
            Hotkey::Undo => Box::new(move || timer.write().undo_split()),
            Hotkey::Skip => Box::new(move || timer.write().skip_split()),
            Hotkey::Pause => Box::new(move || timer.write().toggle_pause_or_start()),
            Hotkey::UndoAllPauses => Box::new(move || timer.write().undo_all_pauses()),
            Hotkey::PreviousComparison => {
                Box::new(move || timer.write().switch_to_previous_comparison())
            }
            Hotkey::NextComparison => Box::new(move || timer.write().switch_to_next_comparison()),
            Hotkey::ToggleTimingMethod => Box::new(move || timer.write().toggle_timing_method()),
        }
    }
}

/// With a Hotkey System the runner can use hotkeys on their keyboard to control
/// the Timer. The hotkeys are global, so the application doesn't need to be in
/// focus. The behavior of the hotkeys depends on the platform and is stubbed
/// out on platforms that don't support hotkeys. You can turn off a Hotkey
/// System temporarily. By default the Hotkey System is activated.
pub struct HotkeySystem {
    config: HotkeyConfig,
    hook: Hook,
    timer: SharedTimer,
    is_active: bool,
}

impl HotkeySystem {
    /// Creates a new Hotkey System for a Timer with the default hotkeys.
    pub fn new(timer: SharedTimer) -> Result<Self> {
        Self::with_config(timer, Default::default())
    }

    /// Creates a new Hotkey System for a Timer with a custom configuration for
    /// the hotkeys.
    pub fn with_config(timer: SharedTimer, config: HotkeyConfig) -> Result<Self> {
        let mut hotkey_system = Self {
            config,
            hook: Hook::new()?,
            timer,
            is_active: false,
        };
        hotkey_system.activate()?;
        Ok(hotkey_system)
    }

    // This method should never be public, because it might mess up the internal state and we might
    // leak a registered hotkey
    unsafe fn register_raw(&mut self, hotkey: Hotkey) -> Result<()> {
        let inner = self.timer.clone();
        if let Some(keycode) = hotkey.get_keycode(&self.config) {
            self.hook.register(keycode, hotkey.callback(inner))?;
        }
        Ok(())
    }

    fn register(&mut self, hotkey: Hotkey, keycode: Option<KeyCode>) -> Result<()> {
        hotkey.set_keycode(&mut self.config, keycode);
        unsafe { self.register_raw(hotkey) }
    }

    // This method should never be public, because it might mess up the internal state and we might
    // leak a registered hotkey
    unsafe fn unregister_raw(&mut self, hotkey: Hotkey) -> Result<()> {
        if let Some(keycode) = hotkey.get_keycode(&self.config) {
            self.hook.unregister(keycode)?;
        }
        Ok(())
    }

    fn unregister(&mut self, hotkey: Hotkey) -> Result<()> {
        hotkey.set_keycode(&mut self.config, None);
        unsafe { self.unregister_raw(hotkey) }
    }

    fn set_hotkey(&mut self, hotkey: Hotkey, keycode: Option<KeyCode>) -> Result<()> {
        // FIXME: We do not check whether the keycode is already in use
        if hotkey.get_keycode(&self.config) == keycode {
            return Ok(());
        }
        if self.is_active {
            self.unregister(hotkey)?;
            self.register(hotkey, keycode)?;
        } else {
            hotkey.set_keycode(&mut self.config, keycode);
        }
        Ok(())
    }

    /// Sets the key to use for splitting and starting a new attempt.
    pub fn set_split(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Split, hotkey)
    }

    /// Sets the key to use for resetting the current attempt.
    pub fn set_reset(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Reset, hotkey)
    }

    /// Sets the key to use for pausing the current attempt and starting a new
    /// attempt.
    pub fn set_pause(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Pause, hotkey)
    }

    /// Sets the key to use for skipping the current split.
    pub fn set_skip(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Skip, hotkey)
    }

    /// Sets the key to use for undoing the last split.
    pub fn set_undo(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Undo, hotkey)
    }

    /// Sets the key to use for switching to the previous comparison.
    pub fn set_previous_comparison(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::PreviousComparison, hotkey)
    }

    /// Sets the key to use for switching to the next comparison.
    pub fn set_next_comparison(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::NextComparison, hotkey)
    }

    /// Sets the key to use for removing all the pause times from the current
    /// time.
    pub fn set_undo_all_pauses(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::UndoAllPauses, hotkey)
    }

    /// Sets the key to use for toggling between the `Real Time` and `Game Time`
    /// timing methods.
    pub fn set_toggle_timing_method(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::ToggleTimingMethod, hotkey)
    }

    /// Deactivates the Hotkey System. No hotkeys will go through until it gets
    /// activated again. If it's already deactivated, nothing happens.
    pub fn deactivate(&mut self) -> Result<()> {
        if self.is_active {
            unsafe {
                self.unregister_raw(Hotkey::Split)?;
                self.unregister_raw(Hotkey::Reset)?;
                self.unregister_raw(Hotkey::Undo)?;
                self.unregister_raw(Hotkey::Skip)?;
                self.unregister_raw(Hotkey::Pause)?;
                self.unregister_raw(Hotkey::UndoAllPauses)?;
                self.unregister_raw(Hotkey::PreviousComparison)?;
                self.unregister_raw(Hotkey::NextComparison)?;
                self.unregister_raw(Hotkey::ToggleTimingMethod)?;
            }
        }
        self.is_active = false;
        Ok(())
    }

    /// Activates a previously deactivated Hotkey System. If it's already
    /// active, nothing happens.
    pub fn activate(&mut self) -> Result<()> {
        if !self.is_active {
            unsafe {
                self.register_raw(Hotkey::Split)?;
                self.register_raw(Hotkey::Reset)?;
                self.register_raw(Hotkey::Undo)?;
                self.register_raw(Hotkey::Skip)?;
                self.register_raw(Hotkey::Pause)?;
                self.register_raw(Hotkey::UndoAllPauses)?;
                self.register_raw(Hotkey::PreviousComparison)?;
                self.register_raw(Hotkey::NextComparison)?;
                self.register_raw(Hotkey::ToggleTimingMethod)?;
            }
        }
        self.is_active = true;
        Ok(())
    }

    /// Returns true if the Hotkey System is active, false otherwise.
    pub const fn is_active(&self) -> bool {
        self.is_active
    }

    /// Returns the hotkey configuration currently in use by the Hotkey System.
    pub const fn config(&self) -> HotkeyConfig {
        self.config
    }

    /// Applies a new hotkey configuration to the Hotkey System. Each hotkey is
    /// changed to the one specified in the configuration. This operation may
    /// fail if you provide a hotkey configuration where a hotkey is used for
    /// multiple operations.
    pub fn set_config(&mut self, config: HotkeyConfig) -> Result<()> {
        self.set_split(config.split)?;
        self.set_reset(config.reset)?;
        self.set_undo(config.undo)?;
        self.set_skip(config.skip)?;
        self.set_pause(config.pause)?;
        self.set_previous_comparison(config.previous_comparison)?;
        self.set_next_comparison(config.next_comparison)?;
        self.set_undo_all_pauses(config.undo_all_pauses)?;
        self.set_toggle_timing_method(config.toggle_timing_method)?;

        Ok(())
    }
}
<commit_msg>Fix Bug when unregistering Hotkey<commit_after>use crate::{
    hotkey::{Hook, KeyCode},
    HotkeyConfig, SharedTimer,
};

pub use crate::hotkey::{Error, Result};

// This enum might be better situated in hotkey_config, but the last method should stay in this file
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Hotkey {
    Split,
    /// The key to use for resetting the current attempt.
    Reset,
    /// The key to use for undoing the last split.
    Undo,
    /// The key to use for skipping the current split.
    Skip,
    /// The key to use for pausing the current attempt and starting a new
    /// attempt.
    Pause,
    /// The key to use for removing all the pause times from the current time.
    UndoAllPauses,
    /// The key to use for switching to the previous comparison.
    PreviousComparison,
    /// The key to use for switching to the next comparison.
    NextComparison,
    /// The key to use for toggling between the `Real Time` and `Game Time`
    /// timing methods.
    ToggleTimingMethod,
}

impl Hotkey {
    fn set_keycode(self, config: &mut HotkeyConfig, keycode: Option<KeyCode>) {
        match self {
            Hotkey::Split => config.split = keycode,
            Hotkey::Reset => config.reset = keycode,
            Hotkey::Undo => config.undo = keycode,
            Hotkey::Skip => config.skip = keycode,
            Hotkey::Pause => config.pause = keycode,
            Hotkey::UndoAllPauses => config.undo_all_pauses = keycode,
            Hotkey::PreviousComparison => config.previous_comparison = keycode,
            Hotkey::NextComparison => config.next_comparison = keycode,
            Hotkey::ToggleTimingMethod => config.toggle_timing_method = keycode,
        }
    }

    const fn get_keycode(self, config: &HotkeyConfig) -> Option<KeyCode> {
        match self {
            Hotkey::Split => config.split,
            Hotkey::Reset => config.reset,
            Hotkey::Undo => config.undo,
            Hotkey::Skip => config.skip,
            Hotkey::Pause => config.pause,
            Hotkey::UndoAllPauses => config.undo_all_pauses,
            Hotkey::PreviousComparison => config.previous_comparison,
            Hotkey::NextComparison => config.next_comparison,
            Hotkey::ToggleTimingMethod => config.toggle_timing_method,
        }
    }

    fn callback(self, timer: SharedTimer) -> Box<dyn FnMut() + Send + 'static> {
        match self {
            Hotkey::Split => Box::new(move || timer.write().split_or_start()),
            Hotkey::Reset => Box::new(move || timer.write().reset(true)),
            Hotkey::Undo => Box::new(move || timer.write().undo_split()),
            Hotkey::Skip => Box::new(move || timer.write().skip_split()),
            Hotkey::Pause => Box::new(move || timer.write().toggle_pause_or_start()),
            Hotkey::UndoAllPauses => Box::new(move || timer.write().undo_all_pauses()),
            Hotkey::PreviousComparison => {
                Box::new(move || timer.write().switch_to_previous_comparison())
            }
            Hotkey::NextComparison => Box::new(move || timer.write().switch_to_next_comparison()),
            Hotkey::ToggleTimingMethod => Box::new(move || timer.write().toggle_timing_method()),
        }
    }
}

/// With a Hotkey System the runner can use hotkeys on their keyboard to control
/// the Timer. The hotkeys are global, so the application doesn't need to be in
/// focus. The behavior of the hotkeys depends on the platform and is stubbed
/// out on platforms that don't support hotkeys. You can turn off a Hotkey
/// System temporarily. By default the Hotkey System is activated.
pub struct HotkeySystem {
    config: HotkeyConfig,
    hook: Hook,
    timer: SharedTimer,
    is_active: bool,
}

impl HotkeySystem {
    /// Creates a new Hotkey System for a Timer with the default hotkeys.
    pub fn new(timer: SharedTimer) -> Result<Self> {
        Self::with_config(timer, Default::default())
    }

    /// Creates a new Hotkey System for a Timer with a custom configuration for
    /// the hotkeys.
    pub fn with_config(timer: SharedTimer, config: HotkeyConfig) -> Result<Self> {
        let mut hotkey_system = Self {
            config,
            hook: Hook::new()?,
            timer,
            is_active: false,
        };
        hotkey_system.activate()?;
        Ok(hotkey_system)
    }

    // This method should never be public, because it might mess up the internal state and we might
    // leak a registered hotkey
    unsafe fn register_raw(&mut self, hotkey: Hotkey) -> Result<()> {
        let inner = self.timer.clone();
        if let Some(keycode) = hotkey.get_keycode(&self.config) {
            self.hook.register(keycode, hotkey.callback(inner))?;
        }
        Ok(())
    }

    fn register(&mut self, hotkey: Hotkey, keycode: Option<KeyCode>) -> Result<()> {
        hotkey.set_keycode(&mut self.config, keycode);
        unsafe { self.register_raw(hotkey) }
    }

    // This method should never be public, because it might mess up the internal state and we might
    // leak a registered hotkey
    unsafe fn unregister_raw(&mut self, hotkey: Hotkey) -> Result<()> {
        if let Some(keycode) = hotkey.get_keycode(&self.config) {
            self.hook.unregister(keycode)?;
        }
        Ok(())
    }

    fn unregister(&mut self, hotkey: Hotkey) -> Result<()> {
        unsafe {
            self.unregister_raw(hotkey)?;
        }
        hotkey.set_keycode(&mut self.config, None);
        Ok(())
    }

    fn set_hotkey(&mut self, hotkey: Hotkey, keycode: Option<KeyCode>) -> Result<()> {
        // FIXME: We do not check whether the keycode is already in use
        if hotkey.get_keycode(&self.config) == keycode {
            return Ok(());
        }
        if self.is_active {
            self.unregister(hotkey)?;
            self.register(hotkey, keycode)?;
        } else {
            hotkey.set_keycode(&mut self.config, keycode);
        }
        Ok(())
    }

    /// Sets the key to use for splitting and starting a new attempt.
    pub fn set_split(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Split, hotkey)
    }

    /// Sets the key to use for resetting the current attempt.
    pub fn set_reset(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Reset, hotkey)
    }

    /// Sets the key to use for pausing the current attempt and starting a new
    /// attempt.
    pub fn set_pause(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Pause, hotkey)
    }

    /// Sets the key to use for skipping the current split.
    pub fn set_skip(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Skip, hotkey)
    }

    /// Sets the key to use for undoing the last split.
    pub fn set_undo(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::Undo, hotkey)
    }

    /// Sets the key to use for switching to the previous comparison.
    pub fn set_previous_comparison(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::PreviousComparison, hotkey)
    }

    /// Sets the key to use for switching to the next comparison.
    pub fn set_next_comparison(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::NextComparison, hotkey)
    }

    /// Sets the key to use for removing all the pause times from the current
    /// time.
    pub fn set_undo_all_pauses(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::UndoAllPauses, hotkey)
    }

    /// Sets the key to use for toggling between the `Real Time` and `Game Time`
    /// timing methods.
    pub fn set_toggle_timing_method(&mut self, hotkey: Option<KeyCode>) -> Result<()> {
        self.set_hotkey(Hotkey::ToggleTimingMethod, hotkey)
    }

    /// Deactivates the Hotkey System. No hotkeys will go through until it gets
    /// activated again. If it's already deactivated, nothing happens.
    pub fn deactivate(&mut self) -> Result<()> {
        if self.is_active {
            unsafe {
                self.unregister_raw(Hotkey::Split)?;
                self.unregister_raw(Hotkey::Reset)?;
                self.unregister_raw(Hotkey::Undo)?;
                self.unregister_raw(Hotkey::Skip)?;
                self.unregister_raw(Hotkey::Pause)?;
                self.unregister_raw(Hotkey::UndoAllPauses)?;
                self.unregister_raw(Hotkey::PreviousComparison)?;
                self.unregister_raw(Hotkey::NextComparison)?;
                self.unregister_raw(Hotkey::ToggleTimingMethod)?;
            }
        }
        self.is_active = false;
        Ok(())
    }

    /// Activates a previously deactivated Hotkey System. If it's already
    /// active, nothing happens.
    pub fn activate(&mut self) -> Result<()> {
        if !self.is_active {
            unsafe {
                self.register_raw(Hotkey::Split)?;
                self.register_raw(Hotkey::Reset)?;
                self.register_raw(Hotkey::Undo)?;
                self.register_raw(Hotkey::Skip)?;
                self.register_raw(Hotkey::Pause)?;
                self.register_raw(Hotkey::UndoAllPauses)?;
                self.register_raw(Hotkey::PreviousComparison)?;
                self.register_raw(Hotkey::NextComparison)?;
                self.register_raw(Hotkey::ToggleTimingMethod)?;
            }
        }
        self.is_active = true;
        Ok(())
    }

    /// Returns true if the Hotkey System is active, false otherwise.
    pub const fn is_active(&self) -> bool {
        self.is_active
    }

    /// Returns the hotkey configuration currently in use by the Hotkey System.
    pub const fn config(&self) -> HotkeyConfig {
        self.config
    }

    /// Applies a new hotkey configuration to the Hotkey System. Each hotkey is
    /// changed to the one specified in the configuration. This operation may
    /// fail if you provide a hotkey configuration where a hotkey is used for
    /// multiple operations.
    pub fn set_config(&mut self, config: HotkeyConfig) -> Result<()> {
        self.set_split(config.split)?;
        self.set_reset(config.reset)?;
        self.set_undo(config.undo)?;
        self.set_skip(config.skip)?;
        self.set_pause(config.pause)?;
        self.set_previous_comparison(config.previous_comparison)?;
        self.set_next_comparison(config.next_comparison)?;
        self.set_undo_all_pauses(config.undo_all_pauses)?;
        self.set_toggle_timing_method(config.toggle_timing_method)?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use formatter::RdbParseFormatter;
use std::io;

pub struct PlainFormatter {
    out: Box<Writer+'static>
}

impl PlainFormatter {
    pub fn new() -> PlainFormatter {
        let out = box io::stdout() as Box<Writer>;
        PlainFormatter { out: out }
    }
}

impl RdbParseFormatter for PlainFormatter {
    fn start_rdb(&mut self) {
        println!("Start of RDB");
    }

    fn end_rdb(&mut self) {
        println!("End of RDB");
    }

    fn checksum(&mut self, checksum: Vec<u8>) {
        println!("Checksum: {}", checksum);
    }

    fn start_database(&mut self, db_number: u32) {
        println!("SELECTDB: {}", db_number);
    }

    fn end_database(&mut self, db_number: u32) {
        println!("END_DB: {}", db_number);
    }

    fn set(&mut self, key: Vec<u8>, value: Vec<u8>) {
        let _ = self.out.write(key[]);
        let _ = self.out.write_str(": ");
        let _ = self.out.flush();

        let _ = self.out.write(value[]);
        let _ = self.out.write_str("\n");
    }

    fn aux_field(&mut self, key: Vec<u8>, value: Vec<u8>) {
        println!("Aux field => {}: {}", key, value);
    }
}
<commit_msg>Write auxiliary fields as they are<commit_after>use formatter::RdbParseFormatter;
use std::io;

pub struct PlainFormatter {
    out: Box<Writer+'static>
}

impl PlainFormatter {
    pub fn new() -> PlainFormatter {
        let out = box io::stdout() as Box<Writer>;
        PlainFormatter { out: out }
    }
}

impl RdbParseFormatter for PlainFormatter {
    fn start_rdb(&mut self) {
        println!("Start of RDB");
    }

    fn end_rdb(&mut self) {
        println!("End of RDB");
    }

    fn checksum(&mut self, checksum: Vec<u8>) {
        println!("Checksum: {}", checksum);
    }

    fn start_database(&mut self, db_number: u32) {
        println!("SELECTDB: {}", db_number);
    }

    fn end_database(&mut self, db_number: u32) {
        println!("END_DB: {}", db_number);
    }

    fn set(&mut self, key: Vec<u8>, value: Vec<u8>) {
        let _ = self.out.write(key[]);
        let _ = self.out.write_str(": ");

        let _ = self.out.write(value[]);
        let _ = self.out.write_str("\n");
        let _ = self.out.flush();
    }

    fn aux_field(&mut self, key: Vec<u8>, value: Vec<u8>) {
        let _ = self.out.write_str("[aux] ");
        let _ = self.out.write(key[]);
        let _ = self.out.write_str(": ");
        let _ = self.out.write(value[]);
        let _ = self.out.write_str("\n");
        let _ = self.out.flush();
    }
}
<|endoftext|>