<commit_before>extern crate errno;

extern crate libc;

use super::constants::*;
use super::ffi::*;

use std::ffi::CString;
use std::os::unix::raw::{gid_t, uid_t};
use std::ptr;
use std::result;
use std::str;

pub type Error = errno::Errno;
pub type Result<T> = result::Result<T, Error>;

fn check_call<T>(res: libc::c_long, value: T) -> Result<T> {
    if res == -1 {
        Err(errno::errno())
    } else {
        Ok(value)
    }
}

fn check_call_ret(res: libc::c_long) -> Result<libc::c_long> {
    if res == -1 {
        Err(errno::errno())
    } else {
        Ok(res)
    }
}

fn get_keyring(id: KeyringSerial, create: bool) -> Result<Keyring> {
    let res = unsafe { keyctl_get_keyring_ID(id, create as libc::c_int) };
    check_call(res as libc::c_long, Keyring { id: res, })
}

pub struct Keyring {
    id: KeyringSerial,
}

impl Keyring {
    pub fn set_default(keyring: DefaultKeyring) -> Result<()> {
        check_call(unsafe { keyctl_set_reqkey_keyring(keyring.serial()) }, ())
    }

    pub fn attach(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, false)
    }

    pub fn attach_or_create(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, true)
    }

    pub fn join_anonymous_session() -> Result<Self> {
        let res = unsafe { keyctl_join_session_keyring(ptr::null()) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn join_session(name: &str) -> Result<Self> {
        let nameptr = CString::new(name).unwrap().as_ptr();
        let res = unsafe { keyctl_join_session_keyring(nameptr) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn clear(&mut self) -> Result<()> {
        check_call(unsafe { keyctl_clear(self.id) }, ())
    }

    pub fn link(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_link(key.id, self.id) }, ())
    }

    pub fn unlink(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_unlink(key.id, self.id) }, ())
    }

    pub fn search(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { keyctl_search(self.id, typeptr, descptr, self.id) };
        check_call(res, Key { id: res as key_serial_t, })
    }

    pub fn read(&self) -> Result<Vec<Key>> {
        let sz = try!(check_call_ret(unsafe { keyctl_read(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_read(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        // TODO: turn bytestream into vec of keys
        unimplemented!()
    }

    pub fn attach_persistent(&mut self) -> Result<Keyring> {
        let res = unsafe { keyctl_get_persistent(-1, self.id) };
        check_call(res, Keyring { id: res as key_serial_t, })
    }

    pub fn add_key(&mut self, type_: &str, description: &str, payload: &[u8]) -> Result<Key> {
        if type_ == "keyring" {
            return Err(errno::Errno(libc::EINVAL));
        }

        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, descptr, payload.as_ptr() as *const libc::c_void, payload.len(), self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn add_keyring(&mut self) -> Result<Keyring> {
        let typeptr = CString::new("keyring").unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, ptr::null(), ptr::null(), 0, self.id) };
        check_call(res as libc::c_long, Keyring { id: res, })
    }

    pub fn find_key(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { find_key_by_type_and_desc(typeptr, descptr, self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn request_key(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { request_key(typeptr, descptr, ptr::null(), self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn request_key_with_fallback(&mut self, type_: &str, description: &str, info: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let infoptr = CString::new(info).unwrap().as_ptr();
        let res = unsafe { request_key(typeptr, descptr, infoptr, self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }
}

pub struct Key {
    id: KeyringSerial,
}

impl Key {
    pub fn request(type_: &str, description: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.request_key(type_, description)
    }

    pub fn request_with_fallback(type_: &str, description: &str, info: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.request_key_with_fallback(type_, description, info)
    }

    pub fn find(type_: &str, description: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.find_key(type_, description)
    }

    pub fn search(type_: &str, description: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.search(type_, description)
    }

    pub fn keyring(&self) -> Result<Keyring> {
        get_keyring(self.id, false)
    }

    pub fn update(&mut self, data: &[u8]) -> Result<()> {
        check_call(unsafe { keyctl_update(self.id, data.as_ptr() as *const libc::c_void, data.len()) }, ())
    }

    pub fn revoke(self) -> Result<()> {
        check_call(unsafe { keyctl_revoke(self.id) }, ())
    }

    pub fn chown(&mut self, uid: uid_t) -> Result<()> {
        check_call(unsafe { keyctl_chown(self.id, uid, -1) }, ())
    }

    pub fn chgrp(&mut self, gid: gid_t) -> Result<()> {
        check_call(unsafe { keyctl_chown(self.id, -1, gid) }, ())
    }

    pub fn set_permissions(&mut self, perms: KeyPermissions) -> Result<()> {
        check_call(unsafe { keyctl_setperm(self.id, perms) }, ())
    }

    pub fn description(&self) -> Result<KeyDescription> {
        self.description_raw().map(|desc| {
            KeyDescription::parse(desc)
        })
    }

    fn description_raw(&self) -> Result<String> {
        let sz = try!(check_call_ret(unsafe { keyctl_describe(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_describe(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn read(&self) -> Result<Vec<u8>> {
        let sz = try!(check_call_ret(unsafe { keyctl_read(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_read(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        Ok(buffer)
    }

    pub fn set_timeout(&mut self, timeout: u32) -> Result<()> {
        check_call(unsafe { keyctl_set_timeout(self.id, timeout) }, ())
    }

    pub fn get_security(&self) -> Result<String> {
        let sz = try!(check_call_ret(unsafe { keyctl_get_security(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_get_security(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn invalidate(self) -> Result<()> {
        check_call(unsafe { keyctl_invalidate(self.id) }, ())
    }

    pub fn manage(&mut self) -> Result<KeyManager> {
        check_call(unsafe { keyctl_assume_authority(self.id) }, KeyManager {
            key: Key {
                id: self.id,
            },
        })
    }
}

pub struct KeyDescription {
    pub type_:          String,
    pub uid:            uid_t,
    pub gid:            gid_t,
    pub perms:          KeyPermissions,
    pub description:    String,
}

impl KeyDescription {
    fn parse(desc: String) -> KeyDescription {
        unimplemented!()
    }
}

pub struct KeyManager {
    key: Key,
}

impl KeyManager {
    pub fn instantiate(self, keyring: &Keyring, payload: &[u8]) -> Result<()> {
        check_call(unsafe { keyctl_instantiate(self.key.id, payload.as_ptr() as *const libc::c_void, payload.len(), keyring.id) }, ())
    }

    pub fn reject(self, keyring: &Keyring, timeout: u32, error: errno::Errno) -> Result<()> {
        let errno::Errno(errval) = error;
        check_call(unsafe { keyctl_reject(self.key.id, timeout, errval as u32, keyring.id) }, ())
    }

    pub fn negate(self, keyring: &Keyring, timeout: u32) -> Result<()> {
        check_call(unsafe { keyctl_negate(self.key.id, timeout, keyring.id) }, ())
    }
}
<commit_msg>api: add methods for unlinking a key from keyrings<commit_after>extern crate errno;

extern crate libc;

use super::constants::*;
use super::ffi::*;

use std::ffi::CString;
use std::os::unix::raw::{gid_t, uid_t};
use std::ptr;
use std::result;
use std::str;

pub type Error = errno::Errno;
pub type Result<T> = result::Result<T, Error>;

fn check_call<T>(res: libc::c_long, value: T) -> Result<T> {
    if res == -1 {
        Err(errno::errno())
    } else {
        Ok(value)
    }
}

fn check_call_ret(res: libc::c_long) -> Result<libc::c_long> {
    if res == -1 {
        Err(errno::errno())
    } else {
        Ok(res)
    }
}

fn get_keyring(id: KeyringSerial, create: bool) -> Result<Keyring> {
    let res = unsafe { keyctl_get_keyring_ID(id, create as libc::c_int) };
    check_call(res as libc::c_long, Keyring { id: res, })
}

pub struct Keyring {
    id: KeyringSerial,
}

impl Keyring {
    pub fn set_default(keyring: DefaultKeyring) -> Result<()> {
        check_call(unsafe { keyctl_set_reqkey_keyring(keyring.serial()) }, ())
    }

    pub fn attach(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, false)
    }

    pub fn attach_or_create(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, true)
    }

    pub fn join_anonymous_session() -> Result<Self> {
        let res = unsafe { keyctl_join_session_keyring(ptr::null()) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn join_session(name: &str) -> Result<Self> {
        let nameptr = CString::new(name).unwrap().as_ptr();
        let res = unsafe { keyctl_join_session_keyring(nameptr) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn clear(&mut self) -> Result<()> {
        check_call(unsafe { keyctl_clear(self.id) }, ())
    }

    pub fn link(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_link(key.id, self.id) }, ())
    }

    pub fn unlink(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_unlink(key.id, self.id) }, ())
    }

    pub fn search(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { keyctl_search(self.id, typeptr, descptr, self.id) };
        check_call(res, Key { id: res as key_serial_t, })
    }

    pub fn read(&self) -> Result<Vec<Key>> {
        let sz = try!(check_call_ret(unsafe { keyctl_read(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_read(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        // TODO: turn bytestream into vec of keys
        unimplemented!()
    }

    pub fn attach_persistent(&mut self) -> Result<Keyring> {
        let res = unsafe { keyctl_get_persistent(-1, self.id) };
        check_call(res, Keyring { id: res as key_serial_t, })
    }

    pub fn add_key(&mut self, type_: &str, description: &str, payload: &[u8]) -> Result<Key> {
        if type_ == "keyring" {
            return Err(errno::Errno(libc::EINVAL));
        }

        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, descptr, payload.as_ptr() as *const libc::c_void, payload.len(), self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn add_keyring(&mut self) -> Result<Keyring> {
        let typeptr = CString::new("keyring").unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, ptr::null(), ptr::null(), 0, self.id) };
        check_call(res as libc::c_long, Keyring { id: res, })
    }

    pub fn find_key(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { find_key_by_type_and_desc(typeptr, descptr, self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn request_key(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { request_key(typeptr, descptr, ptr::null(), self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn request_key_with_fallback(&mut self, type_: &str, description: &str, info: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let infoptr = CString::new(info).unwrap().as_ptr();
        let res = unsafe { request_key(typeptr, descptr, infoptr, self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }
}

pub struct Key {
    id: KeyringSerial,
}

extern fn unlink_cb(
    parent:     key_serial_t,
    key:        key_serial_t,
    desc:       *mut libc::c_char,
    desc_len:   libc::c_int,
    data:       *mut libc::c_void)
    -> libc::c_int {
    unimplemented!()
}

impl Key {
    pub fn request(type_: &str, description: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.request_key(type_, description)
    }

    pub fn request_with_fallback(type_: &str, description: &str, info: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.request_key_with_fallback(type_, description, info)
    }

    pub fn find(type_: &str, description: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.find_key(type_, description)
    }

    pub fn search(type_: &str, description: &str) -> Result<Key> {
        let mut keyring = Keyring { id: 0, };
        keyring.search(type_, description)
    }

    pub fn keyring(&self) -> Result<Keyring> {
        get_keyring(self.id, false)
    }

    pub fn update(&mut self, data: &[u8]) -> Result<()> {
        check_call(unsafe { keyctl_update(self.id, data.as_ptr() as *const libc::c_void, data.len()) }, ())
    }

    pub fn unlink_from(&mut self, keyring: &mut Keyring) -> usize {
        let data: *mut KeyringSerial = &mut self.id;
        let ret = unsafe { recursive_key_scan(keyring.id, unlink_cb, data as *mut libc::c_void) };
        ret as usize
    }

    pub fn unlink_from_session(&mut self) -> usize {
        let data: *mut KeyringSerial = &mut self.id;
        let ret = unsafe { recursive_session_key_scan(unlink_cb, data as *mut libc::c_void) };
        ret as usize
    }

    pub fn revoke(self) -> Result<()> {
        check_call(unsafe { keyctl_revoke(self.id) }, ())
    }

    pub fn chown(&mut self, uid: uid_t) -> Result<()> {
        check_call(unsafe { keyctl_chown(self.id, uid, -1) }, ())
    }

    pub fn chgrp(&mut self, gid: gid_t) -> Result<()> {
        check_call(unsafe { keyctl_chown(self.id, -1, gid) }, ())
    }

    pub fn set_permissions(&mut self, perms: KeyPermissions) -> Result<()> {
        check_call(unsafe { keyctl_setperm(self.id, perms) }, ())
    }

    pub fn description(&self) -> Result<KeyDescription> {
        self.description_raw().map(|desc| {
            KeyDescription::parse(desc)
        })
    }

    fn description_raw(&self) -> Result<String> {
        let sz = try!(check_call_ret(unsafe { keyctl_describe(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_describe(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn read(&self) -> Result<Vec<u8>> {
        let sz = try!(check_call_ret(unsafe { keyctl_read(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_read(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        Ok(buffer)
    }

    pub fn set_timeout(&mut self, timeout: u32) -> Result<()> {
        check_call(unsafe { keyctl_set_timeout(self.id, timeout) }, ())
    }

    pub fn get_security(&self) -> Result<String> {
        let sz = try!(check_call_ret(unsafe { keyctl_get_security(self.id, ptr::null_mut(), 0) }));
        let mut buffer = Vec::with_capacity(sz as usize);
        try!(check_call_ret(unsafe { keyctl_get_security(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn invalidate(self) -> Result<()> {
        check_call(unsafe { keyctl_invalidate(self.id) }, ())
    }

    pub fn manage(&mut self) -> Result<KeyManager> {
        check_call(unsafe { keyctl_assume_authority(self.id) }, KeyManager {
            key: Key {
                id: self.id,
            },
        })
    }
}

pub struct KeyDescription {
    pub type_:          String,
    pub uid:            uid_t,
    pub gid:            gid_t,
    pub perms:          KeyPermissions,
    pub description:    String,
}

impl KeyDescription {
    fn parse(desc: String) -> KeyDescription {
        unimplemented!()
    }
}

pub struct KeyManager {
    key: Key,
}

impl KeyManager {
    pub fn instantiate(self, keyring: &Keyring, payload: &[u8]) -> Result<()> {
        check_call(unsafe { keyctl_instantiate(self.key.id, payload.as_ptr() as *const libc::c_void, payload.len(), keyring.id) }, ())
    }

    pub fn reject(self, keyring: &Keyring, timeout: u32, error: errno::Errno) -> Result<()> {
        let errno::Errno(errval) = error;
        check_call(unsafe { keyctl_reject(self.key.id, timeout, errval as u32, keyring.id) }, ())
    }

    pub fn negate(self, keyring: &Keyring, timeout: u32) -> Result<()> {
        check_call(unsafe { keyctl_negate(self.key.id, timeout, keyring.id) }, ())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 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 target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        pre_link_args: vec!(
            // GNU-style linkers will use this to omit linking to libraries
            // which don't actually fulfill any relocations, but only for
            // libraries which follow this flag.  Thus, use it before
            // specifying libraries to link to.
            "-Wl,--as-needed".to_string(),
        ),
        position_independent_executables: true,
        archive_format: "bsd".to_string(),
        .. Default::default()
    }
}
<commit_msg>fixes #27124 for openbsd<commit_after>// Copyright 2014-2015 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 target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        pre_link_args: vec!(
            // GNU-style linkers will use this to omit linking to libraries
            // which don't actually fulfill any relocations, but only for
            // libraries which follow this flag.  Thus, use it before
            // specifying libraries to link to.
            "-Wl,--as-needed".to_string(),
        ),
        position_independent_executables: true,
        archive_format: "gnu".to_string(),
        .. Default::default()
    }
}
<|endoftext|>


<commit_before>#![doc="SciRust API
"]

pub use error::SRError;

// Number library
pub use algebra::*;

// Matrix library
pub use matrix::*;
pub use matrix::matrix::*;
pub use matrix::traits::*;
pub use matrix::constructors::*;
pub use matrix::view::*;
pub use matrix::iter::*;
pub use matrix::random::*;
pub use matrix::triangular_matrix::*;
pub use matrix::vector::*;
pub use matrix::matrix_conversion::*;
pub use matrix::matrix_minmax::*;
pub use matrix::view_conversion::*;
pub use matrix::view_minmax::*;
pub use matrix::eo::*;

// Linear algebra library
// pub use linalg::linear_system::*;
// pub use linalg::lu::*;
// pub use linalg::singularity::*;
// pub use linalg::inverse::*;
// pub use linalg::rank::*;

// Statistics library
//pub use stat::moments::matrix_moments::*;

<commit_msg>restored linear algebra in API<commit_after>#![doc="SciRust API
"]

pub use error::SRError;

// Number library
pub use algebra::*;

// Matrix library
pub use matrix::*;
pub use matrix::matrix::*;
pub use matrix::traits::*;
pub use matrix::constructors::*;
pub use matrix::view::*;
pub use matrix::iter::*;
pub use matrix::random::*;
pub use matrix::triangular_matrix::*;
pub use matrix::vector::*;
pub use matrix::matrix_conversion::*;
pub use matrix::matrix_minmax::*;
pub use matrix::view_conversion::*;
pub use matrix::view_minmax::*;
pub use matrix::eo::*;

// Linear algebra library
pub use linalg::linear_system::*;
pub use linalg::lu::*;
pub use linalg::singularity::*;
pub use linalg::inverse::*;
pub use linalg::rank::*;

// Statistics library
pub use stat::moments::matrix_moments::*;

<|endoftext|>


<commit_before>use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),
            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),
            // Do not use the standard system startup files or libraries when linking
            "-nostdlib".to_string(),
        ],
    );

    let mut late_link_args = LinkArgs::new();
    let mut late_link_args_dynamic = LinkArgs::new();
    let mut late_link_args_static = LinkArgs::new();
    late_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            "-lmingwex".to_string(),
            "-lmingw32".to_string(),
            "-lmsvcrt".to_string(),
            // mingw's msvcrt is a weird hybrid import library and static library.
            // And it seems that the linker fails to use import symbols from msvcrt
            // that are required from functions in msvcrt in certain cases. For example
            // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
            // Listing the library twice seems to fix that, and seems to also be done
            // by mingw's gcc (Though not sure if it's done on purpose, or by mistake).
            //
            // See https://github.com/rust-lang/rust/pull/47483
            "-lmsvcrt".to_string(),
            "-luser32".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_dynamic.insert(
        LinkerFlavor::Gcc,
        vec![
            // If any of our crates are dynamically linked then we need to use
            // the shared libgcc_s-dw2-1.dll. This is required to support
            // unwinding across DLL boundaries.
            "-lgcc_s".to_string(),
            "-lgcc".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_static.insert(
        LinkerFlavor::Gcc,
        vec![
            // If all of our crates are statically linked then we can get away
            // with statically linking the libgcc unwinding code. This allows
            // binaries to be redistributed without the libgcc_s-dw2-1.dll
            // dependency, but unfortunately break unwinding across DLL
            // boundaries when unwinding across FFI boundaries.
            "-lgcc".to_string(),
            "-lgcc_eh".to_string(),
            "-lpthread".to_string(),
            "-lkernel32".to_string(),
        ],
    );

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: Some("gcc".to_string()),
        dynamic_linking: true,
        executables: true,
        dll_prefix: String::new(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: String::new(),
        staticlib_suffix: ".lib".to_string(),
        no_default_libraries: true,
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects_exe: vec![
            "crt2.o".to_string(),    // mingw C runtime initialization for executables
            "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
        ],
        pre_link_objects_dll: vec![
            "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
            "rsbegin.o".to_string(),
        ],
        late_link_args,
        late_link_args_dynamic,
        late_link_args_static,
        post_link_objects: vec!["rsend.o".to_string()],
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        requires_uwtable: true,

        ..Default::default()
    }
}
<commit_msg>Rollup merge of #70605 - Amanieu:pthread_msvcrt, r=varkor<commit_after>use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),
            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),
            // Do not use the standard system startup files or libraries when linking
            "-nostdlib".to_string(),
        ],
    );

    let mut late_link_args = LinkArgs::new();
    let mut late_link_args_dynamic = LinkArgs::new();
    let mut late_link_args_static = LinkArgs::new();
    late_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            "-lmingwex".to_string(),
            "-lmingw32".to_string(),
            "-lmsvcrt".to_string(),
            // mingw's msvcrt is a weird hybrid import library and static library.
            // And it seems that the linker fails to use import symbols from msvcrt
            // that are required from functions in msvcrt in certain cases. For example
            // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
            // Listing the library twice seems to fix that, and seems to also be done
            // by mingw's gcc (Though not sure if it's done on purpose, or by mistake).
            //
            // See https://github.com/rust-lang/rust/pull/47483
            "-lmsvcrt".to_string(),
            "-luser32".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_dynamic.insert(
        LinkerFlavor::Gcc,
        vec![
            // If any of our crates are dynamically linked then we need to use
            // the shared libgcc_s-dw2-1.dll. This is required to support
            // unwinding across DLL boundaries.
            "-lgcc_s".to_string(),
            "-lgcc".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_static.insert(
        LinkerFlavor::Gcc,
        vec![
            // If all of our crates are statically linked then we can get away
            // with statically linking the libgcc unwinding code. This allows
            // binaries to be redistributed without the libgcc_s-dw2-1.dll
            // dependency, but unfortunately break unwinding across DLL
            // boundaries when unwinding across FFI boundaries.
            "-lgcc".to_string(),
            "-lgcc_eh".to_string(),
            "-lpthread".to_string(),
            // libpthread depends on libmsvcrt, so we need to link it *again*.
            "-lmsvcrt".to_string(),
            "-lkernel32".to_string(),
        ],
    );

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: Some("gcc".to_string()),
        dynamic_linking: true,
        executables: true,
        dll_prefix: String::new(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: String::new(),
        staticlib_suffix: ".lib".to_string(),
        no_default_libraries: true,
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects_exe: vec![
            "crt2.o".to_string(),    // mingw C runtime initialization for executables
            "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
        ],
        pre_link_objects_dll: vec![
            "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
            "rsbegin.o".to_string(),
        ],
        late_link_args,
        late_link_args_dynamic,
        late_link_args_static,
        post_link_objects: vec!["rsend.o".to_string()],
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        requires_uwtable: true,

        ..Default::default()
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Chris Liebert

// Frustum extracting and testing algorithm used from
// http://www.racer.nl/reference/vfc_markmorley.htm

/// `Frustum`
///
/// A data structure for six planes of the view frustum
///
#[allow(unused)]
#[derive(Debug)]
pub struct Frustum {
    // right left bottom top near and far planes
    planes:	[[f32; 4]; 6],
}

#[allow(unused)]
impl Frustum {
    /// Create a frustum given the product of the modelview and projection as a float array
    ///
    #[inline]
    pub fn from_modelview_projection(clip: &[f32; 16]) -> Frustum {
        // Extract the numbers for the RIGHT plane
        let rdx: f32 = clip[3] - clip[0];
        let rdy: f32 = clip[7] - clip[4];
        let rdz: f32 = clip[11] - clip[8];
        let rdw: f32 = clip[15] - clip[12];

        // Divisor to normilize right plane
        let rd: f32 = (rdx.powi(2) + rdy.powi(2) + rdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: right plane divisor cannot be 0");

        // Extract the numbers for the LEFT plane
        let ldx: f32 = clip[3] + clip[0];
        let ldy: f32 = clip[7] + clip[4];
        let ldz: f32 = clip[11] + clip[8];
        let ldw: f32 = clip[15] + clip[12];

        // Divisor to normilize left plane
        let ld: f32 = (ldx.powi(2) + ldy.powi(2) + ldz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: left plane divisor cannot be 0");

        // Extract the BOTTOM plane
        let bdx: f32 = clip[3] + clip[1];
        let bdy: f32 = clip[7] + clip[5];
        let bdz: f32 = clip[11] + clip[9];
        let bdw: f32 = clip[15] + clip[13];

        // Divisor to normilize bottom plane
        let bd: f32 = (bdx.powi(2) + bdy.powi(2) + bdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: bottom plane divisor cannot be 0");

        // Extract the TOP plane
        let tdx: f32 = clip[3] - clip[1];
        let tdy: f32 = clip[7] - clip[5];
        let tdz: f32 = clip[11] - clip[9];
        let tdw: f32 = clip[15] - clip[13];

        // Divisor to normilize top plane
        let td: f32 = (tdx.powi(2) + tdy.powi(2) + tdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: top plane divisor cannot be 0");

        // Extract the FAR plane
        let fdx: f32 = clip[3] - clip[2];
        let fdy: f32 = clip[7] - clip[6];
        let fdz: f32 = clip[11] - clip[10];
        let fdw: f32 = clip[15] - clip[14];

        // Divisor to normilize far plane
        let fd: f32 = (fdx.powi(2) + fdy.powi(2) + fdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: far plane divisor cannot be 0");

        // Extract the NEAR plane
        let ndx: f32 = clip[3] + clip[2];
        let ndy: f32 = clip[7] + clip[6];
        let ndz: f32 = clip[11] + clip[10];
        let ndw: f32 = clip[15] + clip[14];

        // Divisor to normilize near plane
        let nd: f32 = (ndx.powi(2) + ndy.powi(2) + ndz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: near plane divisor cannot be 0");

        Frustum {
            planes: [[rdx / rd, rdy / rd, rdz / rd, rdw / rd],
                     [ldx / ld, ldy / ld, ldz / ld, ldw / ld],
                     [bdx / bd, bdy / bd, bdz / bd, bdw / bd],
                     [tdx / td, tdy / td, tdz / td, tdw / td],
                     [fdx / fd, fdy / fd, fdz / fd, fdw / fd],
                     [ndx / nd, ndy / nd, ndz / nd, ndw / nd]],
        }
    }

    /// Create a frustum from column major modelview and projection float arrays matrices
    ///
    pub fn from_modelview_and_projection(modl: &[f32; 16], proj: &[f32; 16]) -> Frustum {

        // clip = projection * modelview modelview
        let clip: [f32; 16] = [
            modl[0]		* proj[0] + modl[1] 	* proj[4] + modl[2]		* proj[8]	+ modl[3]	* proj[12],
            modl[0]		* proj[1] + modl[1] 	* proj[5] + modl[2] 	* proj[9]	+ modl[3]	* proj[13],
            modl[0]		* proj[2] + modl[1] 	* proj[6] + modl[2] 	* proj[10]	+ modl[3]	* proj[14],
            modl[0]		* proj[3] + modl[1] 	* proj[7] + modl[2] 	* proj[11]	+ modl[3]	* proj[15],
            modl[4]		* proj[0] + modl[5] 	* proj[4] + modl[6] 	* proj[8]	+ modl[7]	* proj[12],
            modl[4]		* proj[1] + modl[5] 	* proj[5] + modl[6] 	* proj[9]	+ modl[7]	* proj[13],
            modl[4]		* proj[2] + modl[5] 	* proj[6] + modl[6] 	* proj[10]	+ modl[7]	* proj[14],
            modl[4]		* proj[3] + modl[5] 	* proj[7] + modl[6] 	* proj[11]	+ modl[7]	* proj[15],
            modl[8]		* proj[0] + modl[9] 	* proj[4] + modl[10]	* proj[8]	+ modl[11]	* proj[12],
            modl[8]		* proj[1] + modl[9] 	* proj[5] + modl[10] 	* proj[9]	+ modl[11]	* proj[13],
            modl[8]		* proj[2] + modl[9] 	* proj[6] + modl[10] 	* proj[10]	+ modl[11]	* proj[14],
            modl[8]		* proj[3] + modl[9] 	* proj[7] + modl[10] 	* proj[11]	+ modl[11]	* proj[15],
            modl[12]	* proj[0] + modl[13]	* proj[4] + modl[14] 	* proj[8]	+ modl[15]	* proj[12],
            modl[12]	* proj[1] + modl[13]	* proj[5] + modl[14] 	* proj[9]	+ modl[15]	* proj[13],
            modl[12]	* proj[2] + modl[13]	* proj[6] + modl[14] 	* proj[10]	+ modl[15]	* proj[14],
            modl[12]	* proj[3] + modl[13]	* proj[7] + modl[14] 	* proj[11]	+ modl[15]	* proj[15],
        ];
        Frustum::from_modelview_projection(&clip)
    }

    /// Create a frustum from 2-dimensional column-major modelview and projection float arrays
    ///
    pub fn from_modelview_and_projection_2d(modl: &[[f32; 4]; 4], proj: &[[f32; 4]; 4]) -> Frustum {
        let modl_1d: [f32; 16] = [
            modl[0][0],
            modl[0][1],
            modl[0][2],
            modl[0][3],
                modl[1][0],
                modl[1][1],
                modl[1][2],
                modl[1][3],
                    modl[2][0],
                    modl[2][1],
                    modl[2][2],
                    modl[2][3],
                        modl[3][0],
                        modl[3][1],
                        modl[3][2],
                        modl[3][3],
        ];
        let proj_1d: [f32; 16] = [
            proj[0][0],
            proj[0][1],
            proj[0][2],
            proj[0][3],
                proj[1][0],
                proj[1][1],
                proj[1][2],
                proj[1][3],
                    proj[2][0],
                    proj[2][1],
                    proj[2][2],
                    proj[2][3],
                        proj[3][0],
                        proj[3][1],
                        proj[3][2],
                        proj[3][3],
        ];

        return Frustum::from_modelview_and_projection(&modl_1d, &proj_1d);
    }

    /// A point is intersecting the renderable region of the frustum
    ///
    pub fn point_intersecting(&self, x: &f32, y: &f32, z: &f32) -> bool {
        for p in 0..6 {
            if (self.planes[p][0] * x + self.planes[p][1] * y + self.planes[p][2] * z + self.planes[p][3]) <= 0.0f32 {
                return false;
            }
        }
        true
    }

    /// A sphere is intersecting the renderable region of the frustum
    ///
    pub fn sphere_intersecting(&self, x: &f32, y: &f32, z: &f32, r: &f32) -> bool {
        for p in 0..6 {
            if self.planes[p][0] * x + self.planes[p][1] * y + self.planes[p][2] * z + self.planes[p][3] <= (0.0f32 - r) {
                return false;
            }
        }
        true
    }
}<commit_msg>Whitespace update<commit_after>// Copyright (C) 2017 Chris Liebert

// Frustum extracting and testing algorithm used from
// http://www.racer.nl/reference/vfc_markmorley.htm

/// `Frustum`
///
/// A data structure for six planes of the view frustum
///
#[allow(unused)]
#[derive(Debug)]
pub struct Frustum {
    // right left bottom top near and far planes
    planes:	[[f32; 4]; 6],
}

#[allow(unused)]
impl Frustum {
    /// Create a frustum given the product of the modelview and projection as a float array
    ///
    #[inline]
    pub fn from_modelview_projection(clip: &[f32; 16]) -> Frustum {
        // Extract the numbers for the RIGHT plane
        let rdx: f32 = clip[3] - clip[0];
        let rdy: f32 = clip[7] - clip[4];
        let rdz: f32 = clip[11] - clip[8];
        let rdw: f32 = clip[15] - clip[12];

        // Divisor to normilize right plane
        let rd: f32 = (rdx.powi(2) + rdy.powi(2) + rdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: right plane divisor cannot be 0");

        // Extract the numbers for the LEFT plane
        let ldx: f32 = clip[3] + clip[0];
        let ldy: f32 = clip[7] + clip[4];
        let ldz: f32 = clip[11] + clip[8];
        let ldw: f32 = clip[15] + clip[12];

        // Divisor to normilize left plane
        let ld: f32 = (ldx.powi(2) + ldy.powi(2) + ldz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: left plane divisor cannot be 0");

        // Extract the BOTTOM plane
        let bdx: f32 = clip[3] + clip[1];
        let bdy: f32 = clip[7] + clip[5];
        let bdz: f32 = clip[11] + clip[9];
        let bdw: f32 = clip[15] + clip[13];

        // Divisor to normilize bottom plane
        let bd: f32 = (bdx.powi(2) + bdy.powi(2) + bdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: bottom plane divisor cannot be 0");

        // Extract the TOP plane
        let tdx: f32 = clip[3] - clip[1];
        let tdy: f32 = clip[7] - clip[5];
        let tdz: f32 = clip[11] - clip[9];
        let tdw: f32 = clip[15] - clip[13];

        // Divisor to normilize top plane
        let td: f32 = (tdx.powi(2) + tdy.powi(2) + tdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: top plane divisor cannot be 0");

        // Extract the FAR plane
        let fdx: f32 = clip[3] - clip[2];
        let fdy: f32 = clip[7] - clip[6];
        let fdz: f32 = clip[11] - clip[10];
        let fdw: f32 = clip[15] - clip[14];

        // Divisor to normilize far plane
        let fd: f32 = (fdx.powi(2) + fdy.powi(2) + fdz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: far plane divisor cannot be 0");

        // Extract the NEAR plane
        let ndx: f32 = clip[3] + clip[2];
        let ndy: f32 = clip[7] + clip[6];
        let ndz: f32 = clip[11] + clip[10];
        let ndw: f32 = clip[15] + clip[14];

        // Divisor to normilize near plane
        let nd: f32 = (ndx.powi(2) + ndy.powi(2) + ndz.powi(2)).sqrt();
        debug_assert!(rd > 0.0f32, "Invalid modelview projection matrix: near plane divisor cannot be 0");

        Frustum {
            planes: [[rdx / rd, rdy / rd, rdz / rd, rdw / rd],
                     [ldx / ld, ldy / ld, ldz / ld, ldw / ld],
                     [bdx / bd, bdy / bd, bdz / bd, bdw / bd],
                     [tdx / td, tdy / td, tdz / td, tdw / td],
                     [fdx / fd, fdy / fd, fdz / fd, fdw / fd],
                     [ndx / nd, ndy / nd, ndz / nd, ndw / nd]],
        }
    }

    /// Create a frustum from column major modelview and projection float arrays matrices
    ///
    pub fn from_modelview_and_projection(modl: &[f32; 16], proj: &[f32; 16]) -> Frustum {

        // clip = projection * modelview modelview
        let clip: [f32; 16] = [
            modl[0]	* proj[0] + modl[1] 	* proj[4] + modl[2] 	* proj[8]	+ modl[3]	* proj[12],
            modl[0]	* proj[1] + modl[1] 	* proj[5] + modl[2] 	* proj[9]	+ modl[3]	* proj[13],
            modl[0]	* proj[2] + modl[1] 	* proj[6] + modl[2] 	* proj[10]	+ modl[3]	* proj[14],
            modl[0]	* proj[3] + modl[1] 	* proj[7] + modl[2] 	* proj[11]	+ modl[3]	* proj[15],
            modl[4]	* proj[0] + modl[5] 	* proj[4] + modl[6] 	* proj[8]	+ modl[7]	* proj[12],
            modl[4]	* proj[1] + modl[5] 	* proj[5] + modl[6] 	* proj[9]	+ modl[7]	* proj[13],
            modl[4]	* proj[2] + modl[5] 	* proj[6] + modl[6] 	* proj[10]	+ modl[7]	* proj[14],
            modl[4]	* proj[3] + modl[5] 	* proj[7] + modl[6] 	* proj[11]	+ modl[7]	* proj[15],
            modl[8]	* proj[0] + modl[9] 	* proj[4] + modl[10]	* proj[8]	+ modl[11]	* proj[12],
            modl[8]	* proj[1] + modl[9] 	* proj[5] + modl[10] 	* proj[9]	+ modl[11]	* proj[13],
            modl[8]	* proj[2] + modl[9] 	* proj[6] + modl[10] 	* proj[10]	+ modl[11]	* proj[14],
            modl[8]	* proj[3] + modl[9] 	* proj[7] + modl[10] 	* proj[11]	+ modl[11]	* proj[15],
            modl[12]	* proj[0] + modl[13]	* proj[4] + modl[14] 	* proj[8]	+ modl[15]	* proj[12],
            modl[12]	* proj[1] + modl[13]	* proj[5] + modl[14] 	* proj[9]	+ modl[15]	* proj[13],
            modl[12]	* proj[2] + modl[13]	* proj[6] + modl[14] 	* proj[10]	+ modl[15]	* proj[14],
            modl[12]	* proj[3] + modl[13]	* proj[7] + modl[14] 	* proj[11]	+ modl[15]	* proj[15],
        ];
        Frustum::from_modelview_projection(&clip)
    }

    /// Create a frustum from 2-dimensional column-major modelview and projection float arrays
    ///
    pub fn from_modelview_and_projection_2d(modl: &[[f32; 4]; 4], proj: &[[f32; 4]; 4]) -> Frustum {
        let modl_1d: [f32; 16] = [
            modl[0][0],
            modl[0][1],
            modl[0][2],
            modl[0][3],
                modl[1][0],
                modl[1][1],
                modl[1][2],
                modl[1][3],
                    modl[2][0],
                    modl[2][1],
                    modl[2][2],
                    modl[2][3],
                        modl[3][0],
                        modl[3][1],
                        modl[3][2],
                        modl[3][3],
        ];
        let proj_1d: [f32; 16] = [
            proj[0][0],
            proj[0][1],
            proj[0][2],
            proj[0][3],
                proj[1][0],
                proj[1][1],
                proj[1][2],
                proj[1][3],
                    proj[2][0],
                    proj[2][1],
                    proj[2][2],
                    proj[2][3],
                        proj[3][0],
                        proj[3][1],
                        proj[3][2],
                        proj[3][3],
        ];
        return Frustum::from_modelview_and_projection(&modl_1d, &proj_1d);
    }

    /// A point is intersecting the renderable region of the frustum
    ///
    pub fn point_intersecting(&self, x: &f32, y: &f32, z: &f32) -> bool {
        for p in 0..6 {
            if (self.planes[p][0] * x + self.planes[p][1] * y + self.planes[p][2] * z + self.planes[p][3]) <= 0.0f32 {
                return false;
            }
        }
        true
    }

    /// A sphere is intersecting the renderable region of the frustum
    ///
    pub fn sphere_intersecting(&self, x: &f32, y: &f32, z: &f32, r: &f32) -> bool {
        for p in 0..6 {
            if self.planes[p][0] * x + self.planes[p][1] * y + self.planes[p][2] * z + self.planes[p][3] <= (0.0f32 - r) {
                return false;
            }
        }
        true
    }
}
<|endoftext|>


<commit_before>
// This pass generates x86-64 assembly from IR.

#![allow(non_upper_case_globals)]

use crate::regalloc::*;
use crate::util::*;
use crate::*;
use std::collections::HashMap;

lazy_static! {
    static ref LABEL: Mutex<usize> = Mutex::new(0);
    static ref ESCAPED: Mutex<HashMap<char,char>> = Mutex::new(HashMap::new());
}

const argreg8: [&'static str; 6] = ["dil", "sil", "dl", "cl", "r8b", "r9b"];
const argreg32: [&'static str; 6] = ["edi", "esi", "edx", "ecx", "r8d", "r9d"];
const argreg64: [&'static str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];

fn label() -> usize {
    *LABEL.lock().unwrap()
}

fn init_escaped() {
    let mut escaped = ESCAPED.lock().unwrap();
    if escaped.len() > 0 {
        return;
    }

    escaped.insert(char::from(8), 'b');  // \b
    escaped.insert(char::from(12), 'f'); // \f
    escaped.insert(char::from(10), 'n'); // \n
    escaped.insert(char::from(13), 'r'); // \r
    escaped.insert(char::from(9), 't');  // \t
    escaped.insert('\\', '\\');
    escaped.insert('\'', '\'');
    escaped.insert('\"', '"');
}

fn escaped(c: char) -> Option<char> {
    let mut ret = None;
    match ESCAPED.lock() {
        Ok(escaped) => {
            match escaped.get(&c) {
                Some(esc) => {
                    ret = Some(*esc);
                }
                None => { }
            }
        }
        Err(_) => { }
    }
    return ret;
}

fn inc_label() {
    let mut label = LABEL.lock().unwrap();
    *label += 1;
}

fn escape(s: & String) -> String {
    init_escaped();

    let mut buf = String::new();
    let mut chars = s.chars();
    while let Some(c) = chars.next() {
        if let Some(esc) = escaped(c) {
            buf.push('\\');
            buf.push(esc);
        } else if c.is_ascii_graphic() || c == ' ' {
            buf.push(c);
        } else {
            buf.push_str(&format!("\\{:03o}", u32::from(c)));
        }
    }

    //buf.push(char::from(0));
    return buf;
}

fn emit_cmp(ir: &IR, insn: &str) {
    println!("  cmp {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
    println!("  {} {}", insn, regs8[ir.lhs as usize]);
    println!("  movzb {}, {}", regs[ir.lhs as usize], regs8[ir.lhs as usize]);
}

fn gen(fun: &IR) {
    let ret = format!(".Lend{}", label());
    inc_label();

    println!(".global {}", fun.name);
    println!("{}:", fun.name);
    println!("  push rbp");
    println!("  mov rbp, rsp");
    println!("  sub rsp, {}", roundup(fun.stacksize, 16));
    println!("  push r12");
    println!("  push r13");
    println!("  push r14");
    println!("  push r15");

    for i in 0..fun.ir.len() {
        let ir = &fun.ir[i as usize];
        match ir.op {
            IRType::IMM => {
                println!("  mov {}, {}", regs[ir.lhs as usize], ir.rhs);
            }
            IRType::BPREL => {
                println!("  lea {}, [rbp-{}]", regs[ir.lhs as usize], ir.rhs);
            }
            IRType::MOV => {
                println!("  mov {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
            }
            IRType::RETURN => {
                println!("  mov rax, {}", regs[ir.lhs as usize]);
                println!("  jmp {}", ret);
            }
            IRType::CALL => {
                for i in 0..ir.nargs {
                    println!("  mov {}, {}", argreg64[i], regs[ir.args[i] as usize]);
                }

                println!("  push r10");
                println!("  push r11");
                println!("  mov rax, 0");
                println!("  call {}", ir.name);
                println!("  pop r11");
                println!("  pop r10");

                println!("  mov {}, rax", regs[ir.lhs as usize]);
            }
            IRType::LABEL => {
                println!(".L{}:", ir.lhs);
            }
            IRType::LABEL_ADDR => {
                println!("  lea {}, {}", regs[ir.lhs as usize], ir.name);
            }
            IRType::NEG => {
                println!("  neg {}", regs[ir.lhs as usize]);
            }
            IRType::EQ => {
                emit_cmp(ir, "sete")
            }
            IRType::NE => {
                emit_cmp(ir, "setne")
            }
            IRType::LT => {
                emit_cmp(ir, "setl")
            }
            IRType::LE => {
                emit_cmp(ir, "setle")
            }
            IRType::AND => {
                println!("  and {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
            }
            IRType::OR => {
                println!("  or {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
            }
            IRType::XOR => {
                println!("  xor {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
            }
            IRType::SHL => {
                println!("  mov cl, {}", regs8[ir.rhs as usize]);
                println!("  shl {}, cl", regs[ir.lhs as usize]);
            }
            IRType::SHR => {
                println!("  mov cl, {}", regs8[ir.rhs as usize]);
                println!("  shr {}, cl", regs[ir.lhs as usize]);
            }
            IRType::JMP => {
                println!("  jmp .L{}", ir.lhs);
            }
            IRType::IF => {
                println!("  cmp {}, 0", regs[ir.lhs as usize]);
                println!("  jne .L{}", ir.rhs);
            }
            IRType::UNLESS => {
                println!("  cmp {}, 0", regs[ir.lhs as usize]);
                println!("  je .L{}", ir.rhs);
            }
            IRType::LOAD8 => {
                println!("  mov {}, [{}]", regs8[ir.lhs as usize], regs[ir.rhs as usize]);
                println!("  movzb {}, {}", regs[ir.lhs as usize], regs8[ir.lhs as usize]);
            }
            IRType::LOAD32 => {
                println!(
                    "  mov {}, [{}]",
                    regs32[ir.lhs as usize], regs[ir.rhs as usize]
                );
            }
            IRType::LOAD64 => {
                println!(
                    "  mov {}, [{}]",
                    regs[ir.lhs as usize], regs[ir.rhs as usize]
                );
            }
            IRType::STORE8 => {
                println!(
                    "  mov [{}], {}",
                    regs[ir.lhs as usize], regs8[ir.rhs as usize]
                );

                // fall through in 9cc
                println!(
                    "  mov [{}], {}",
                    regs[ir.lhs as usize], regs32[ir.rhs as usize]
                );
            }
            IRType::STORE32 => {
                println!(
                    "  mov [{}], {}",
                    regs[ir.lhs as usize], regs32[ir.rhs as usize]
                );
            }
            IRType::STORE64 => {
                println!(
                    "  mov [{}], {}",
                    regs[ir.lhs as usize], regs[ir.rhs as usize]
                );
            }
            IRType::STORE8_ARG => {
                println!("  mov [rbp-{}], {}", ir.lhs, argreg8[ir.rhs as usize]);
            }
            IRType::STORE32_ARG => {
                println!("  mov [rbp-{}], {}", ir.lhs, argreg32[ir.rhs as usize]);
            }
            IRType::STORE64_ARG => {
                println!("  mov [rbp-{}], {}", ir.lhs, argreg64[ir.rhs as usize]);
            }
            IRType::ADD => {
                println!("  add {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
            }
            IRType::ADD_IMM => {
                println!("  add {}, {}", regs[ir.lhs as usize], ir.rhs);
            }
            IRType::SUB => {
                println!("  sub {}, {}", regs[ir.lhs as usize], regs[ir.rhs as usize]);
            }
            IRType::SUB_IMM => {
                println!("  sub {}, {}", regs[ir.lhs as usize], ir.rhs);
            }
            IRType::MUL => {
                println!("  mov rax, {}", regs[ir.rhs as usize]);
                println!("  mul {}", regs[ir.lhs as usize]);
                println!("  mov {}, rax", regs[ir.lhs as usize]);
            }
            IRType::MUL_IMM => {
                println!("  mov rax, {}", ir.rhs);
                println!("  mul {}", regs[ir.lhs as usize]);
                println!("  mov {}, rax", regs[ir.lhs as usize]);
            }
            IRType::DIV => {
                println!(" mov rax, {}", regs[ir.lhs as usize]);
                println!(" cqo");
                println!(" div {}", regs[ir.rhs as usize]);
                println!(" mov {}, rax", regs[ir.lhs as usize]);
            }
            IRType::MOD => {
                println!("  mov rax, {}", regs[ir.lhs as usize]);
                println!("  cqo");
                println!("  div {}", regs[ir.rhs as usize]);
                println!("  mov {}, rdx", regs[ir.lhs as usize]);
            }
            IRType::NOP => {}
            ref i => {
                panic!(format!("unknown operator {:?}", i));
            }
        }
    }
    println!("{}:", ret);
    println!("  pop r15");
    println!("  pop r14");
    println!("  pop r13");
    println!("  pop r12");
    println!("  mov rsp, rbp");
    println!("  pop rbp");
    println!("  ret");
}

pub fn gen_x86(globals: Vec<Var>, fns: &Vec<IR>) {
    println!(".intel_syntax noprefix");

    println!(".data");
    for var in globals.iter() {
        if var.is_extern {
            continue;
        }
        println!("{}:", var.name);
        println!("  .ascii \"{}\"", escape(&var.data));
    }

    println!(".text");
    for i in 0..fns.len() {
        gen(&fns[i]);
    }
}
<commit_msg>Use shorter variable name.<commit_after>
// This pass generates x86-64 assembly from IR.

#![allow(non_upper_case_globals)]

use crate::regalloc::*;
use crate::util::*;
use crate::*;
use std::collections::HashMap;

lazy_static! {
    static ref LABEL: Mutex<usize> = Mutex::new(0);
    static ref ESCAPED: Mutex<HashMap<char,char>> = Mutex::new(HashMap::new());
}

const argreg8: [&'static str; 6] = ["dil", "sil", "dl", "cl", "r8b", "r9b"];
const argreg32: [&'static str; 6] = ["edi", "esi", "edx", "ecx", "r8d", "r9d"];
const argreg64: [&'static str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];

fn label() -> usize {
    *LABEL.lock().unwrap()
}

fn init_escaped() {
    let mut escaped = ESCAPED.lock().unwrap();
    if escaped.len() > 0 {
        return;
    }

    escaped.insert(char::from(8), 'b');  // \b
    escaped.insert(char::from(12), 'f'); // \f
    escaped.insert(char::from(10), 'n'); // \n
    escaped.insert(char::from(13), 'r'); // \r
    escaped.insert(char::from(9), 't');  // \t
    escaped.insert('\\', '\\');
    escaped.insert('\'', '\'');
    escaped.insert('\"', '"');
}

fn escaped(c: char) -> Option<char> {
    let mut ret = None;
    match ESCAPED.lock() {
        Ok(escaped) => {
            match escaped.get(&c) {
                Some(esc) => {
                    ret = Some(*esc);
                }
                None => { }
            }
        }
        Err(_) => { }
    }
    return ret;
}

fn inc_label() {
    let mut label = LABEL.lock().unwrap();
    *label += 1;
}

fn escape(s: & String) -> String {
    init_escaped();

    let mut buf = String::new();
    let mut chars = s.chars();
    while let Some(c) = chars.next() {
        if let Some(esc) = escaped(c) {
            buf.push('\\');
            buf.push(esc);
        } else if c.is_ascii_graphic() || c == ' ' {
            buf.push(c);
        } else {
            buf.push_str(&format!("\\{:03o}", u32::from(c)));
        }
    }

    //buf.push(char::from(0));
    return buf;
}

fn emit_cmp(ir: &IR, insn: &str) {
    let lhs = ir.lhs as usize;
    let rhs = ir.rhs as usize;

    println!("  cmp {}, {}", regs[lhs], regs[rhs]);
    println!("  {} {}", insn, regs8[lhs]);
    println!("  movzb {}, {}", regs[lhs], regs8[lhs]);
}

fn gen(fun: &IR) {
    let ret = format!(".Lend{}", label());
    inc_label();

    println!(".global {}", fun.name);
    println!("{}:", fun.name);
    println!("  push rbp");
    println!("  mov rbp, rsp");
    println!("  sub rsp, {}", roundup(fun.stacksize, 16));
    println!("  push r12");
    println!("  push r13");
    println!("  push r14");
    println!("  push r15");

    for i in 0..fun.ir.len() {
        let ir = &fun.ir[i as usize];
        let lhs = ir.lhs as usize;
        let rhs = ir.rhs as usize;

        match ir.op {
            IRType::IMM => {
                println!("  mov {}, {}", regs[lhs], rhs);
            }
            IRType::BPREL => {
                println!("  lea {}, [rbp-{}]", regs[lhs], rhs);
            }
            IRType::MOV => {
                println!("  mov {}, {}", regs[lhs], regs[rhs]);
            }
            IRType::RETURN => {
                println!("  mov rax, {}", regs[lhs]);
                println!("  jmp {}", ret);
            }
            IRType::CALL => {
                for i in 0..ir.nargs {
                    println!("  mov {}, {}", argreg64[i], regs[ir.args[i] as usize]);
                }

                println!("  push r10");
                println!("  push r11");
                println!("  mov rax, 0");
                println!("  call {}", ir.name);
                println!("  pop r11");
                println!("  pop r10");

                println!("  mov {}, rax", regs[lhs]);
            }
            IRType::LABEL => {
                println!(".L{}:", lhs);
            }
            IRType::LABEL_ADDR => {
                println!("  lea {}, {}", regs[lhs], ir.name);
            }
            IRType::NEG => {
                println!("  neg {}", regs[lhs]);
            }
            IRType::EQ => {
                emit_cmp(ir, "sete")
            }
            IRType::NE => {
                emit_cmp(ir, "setne")
            }
            IRType::LT => {
                emit_cmp(ir, "setl")
            }
            IRType::LE => {
                emit_cmp(ir, "setle")
            }
            IRType::AND => {
                println!("  and {}, {}", regs[lhs], regs[rhs]);
            }
            IRType::OR => {
                println!("  or {}, {}", regs[lhs], regs[rhs]);
            }
            IRType::XOR => {
                println!("  xor {}, {}", regs[lhs], regs[rhs]);
            }
            IRType::SHL => {
                println!("  mov cl, {}", regs8[rhs]);
                println!("  shl {}, cl", regs[lhs]);
            }
            IRType::SHR => {
                println!("  mov cl, {}", regs8[rhs]);
                println!("  shr {}, cl", regs[lhs]);
            }
            IRType::JMP => {
                println!("  jmp .L{}", lhs);
            }
            IRType::IF => {
                println!("  cmp {}, 0", regs[lhs]);
                println!("  jne .L{}", rhs);
            }
            IRType::UNLESS => {
                println!("  cmp {}, 0", regs[lhs]);
                println!("  je .L{}", rhs);
            }
            IRType::LOAD8 => {
                println!("  mov {}, [{}]", regs8[lhs], regs[rhs]);
                println!("  movzb {}, {}", regs[lhs], regs8[lhs]);
            }
            IRType::LOAD32 => {
                println!("  mov {}, [{}]", regs32[lhs], regs[rhs]);
            }
            IRType::LOAD64 => {
                println!("  mov {}, [{}]", regs[lhs], regs[rhs]);
            }
            IRType::STORE8 => {
                println!("  mov [{}], {}", regs[lhs], regs8[rhs]);

                // fall through in 9cc
                println!("  mov [{}], {}", regs[lhs], regs32[rhs]);
            }
            IRType::STORE32 => {
                println!("  mov [{}], {}", regs[lhs], regs32[rhs]);
            }
            IRType::STORE64 => {
                println!("  mov [{}], {}", regs[lhs], regs[rhs]);
            }
            IRType::STORE8_ARG => {
                println!("  mov [rbp-{}], {}", lhs, argreg8[rhs]);
            }
            IRType::STORE32_ARG => {
                println!("  mov [rbp-{}], {}", lhs, argreg32[rhs]);
            }
            IRType::STORE64_ARG => {
                println!("  mov [rbp-{}], {}", lhs, argreg64[rhs]);
            }
            IRType::ADD => {
                println!("  add {}, {}", regs[lhs], regs[rhs]);
            }
            IRType::ADD_IMM => {
                println!("  add {}, {}", regs[lhs], rhs);
            }
            IRType::SUB => {
                println!("  sub {}, {}", regs[lhs], regs[rhs]);
            }
            IRType::SUB_IMM => {
                println!("  sub {}, {}", regs[lhs], rhs);
            }
            IRType::MUL => {
                println!("  mov rax, {}", regs[rhs]);
                println!("  mul {}", regs[lhs]);
                println!("  mov {}, rax", regs[lhs]);
            }
            IRType::MUL_IMM => {
                println!("  mov rax, {}", rhs);
                println!("  mul {}", regs[lhs]);
                println!("  mov {}, rax", regs[lhs]);
            }
            IRType::DIV => {
                println!(" mov rax, {}", regs[lhs]);
                println!(" cqo");
                println!(" div {}", regs[rhs]);
                println!(" mov {}, rax", regs[lhs]);
            }
            IRType::MOD => {
                println!("  mov rax, {}", regs[lhs]);
                println!("  cqo");
                println!("  div {}", regs[rhs]);
                println!("  mov {}, rdx", regs[lhs]);
            }
            IRType::NOP => {}
            ref i => {
                panic!(format!("unknown operator {:?}", i));
            }
        }
    }
    println!("{}:", ret);
    println!("  pop r15");
    println!("  pop r14");
    println!("  pop r13");
    println!("  pop r12");
    println!("  mov rsp, rbp");
    println!("  pop rbp");
    println!("  ret");
}

pub fn gen_x86(globals: Vec<Var>, fns: &Vec<IR>) {
    println!(".intel_syntax noprefix");

    println!(".data");
    for var in globals.iter() {
        if var.is_extern {
            continue;
        }
        println!("{}:", var.name);
        println!("  .ascii \"{}\"", escape(&var.data));
    }

    println!(".text");
    for i in 0..fns.len() {
        gen(&fns[i]);
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::cell::RefCell;
use std::rc::Rc;
use std::time::Duration;
use time::precise_time_ns;

use bootstrap::{Context, Keyboard, Mouse, MouseMove, Scroll, Window};
pub use bootstrap::{Action, Key, MouseButton};
use camera::{Camera, Freefly};
use transform::Translation;

#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

/// Class of keyboard handlers.
pub trait KeyboardHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool;
}

impl KeyboardHandler for Unhandled {
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
}

/// Class of mouse button handlers.
pub trait MouseButtonHandler {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool;
}

impl MouseButtonHandler for Unhandled {
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
}

/// Class of mouse move handlers.
pub trait CursorHandler {
  fn on_cursor_move(&mut self, cursor_pos: [f64; 2]) -> bool;
}

impl CursorHandler for Unhandled {
  fn on_cursor_move(&mut self, _: [f64; 2]) -> bool { true }
}

/// Class of scroll handlers.
pub trait ScrollHandler {
  fn on_scroll(&mut self, scroll_dir: [f64; 2]) -> bool;
}

impl ScrollHandler for Unhandled {
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

/// All common stuff goes here.
pub struct App {
  /// Some kind of epoch start the application started at.
  start_time: u64,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
}

impl App {
  pub fn init(kbd: Keyboard, mouse: Mouse, cursor: MouseMove, scroll: Scroll, window: Window) -> Self {
    App {
      start_time: precise_time_ns(),
      kbd: kbd,
      mouse: mouse,
      cursor: cursor,
      scroll: scroll,
      window: window
    }
  }

  pub fn time(&self) -> f32 {
    (precise_time_ns() - self.start_time) as f32 * 1e-9
  }

  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool
      where H: KeyboardHandler + MouseButtonHandler + CursorHandler + ScrollHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !handler.on_cursor_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  pub fn step<R>(&mut self, fps: Option<u32>, mut draw_frame: R) -> bool where R: FnMut(f32) {
    let loop_start_time = precise_time_ns();

    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);

    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps {
      let fps = fps as f32;
      let elapsed_time_ms = ((precise_time_ns() - loop_start_time) as f64 * 1e-6) as i64;
      let sleep_time_ms = (1. / fps * 1e3) as i64 - elapsed_time_ms;

      if sleep_time_ms > 0 {
        thread::sleep(Duration::from_millis(sleep_time_ms as u64));
      }
    }

    true
  }
}

/// Debug handler.
pub struct DebugHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f64; 2]
}

impl DebugHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    DebugHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f64; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx as f32));
    }

    self.last_cursor = cursor;
  }
}

impl KeyboardHandler for DebugHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return false }
    }

    true
  }
}

impl MouseButtonHandler for DebugHandler {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    true
  }
}

impl CursorHandler for DebugHandler {
  fn on_cursor_move(&mut self, dir: [f64; 2]) -> bool {
    self.orient_camera_on_event(dir);
    true
  }
}

impl ScrollHandler for DebugHandler {
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}
<commit_msg>Fixed time.<commit_after>use std::thread;
use std::cell::RefCell;
use std::rc::Rc;
use time::{Duration, SteadyTime};

use bootstrap::{Context, Keyboard, Mouse, MouseMove, Scroll, Window};
pub use bootstrap::{Action, Key, MouseButton};
use camera::{Camera, Freefly};
use transform::Translation;

#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

/// Class of keyboard handlers.
pub trait KeyboardHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool;
}

impl KeyboardHandler for Unhandled {
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
}

/// Class of mouse button handlers.
pub trait MouseButtonHandler {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool;
}

impl MouseButtonHandler for Unhandled {
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
}

/// Class of mouse move handlers.
pub trait CursorHandler {
  fn on_cursor_move(&mut self, cursor_pos: [f64; 2]) -> bool;
}

impl CursorHandler for Unhandled {
  fn on_cursor_move(&mut self, _: [f64; 2]) -> bool { true }
}

/// Class of scroll handlers.
pub trait ScrollHandler {
  fn on_scroll(&mut self, scroll_dir: [f64; 2]) -> bool;
}

impl ScrollHandler for Unhandled {
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

/// All common stuff goes here.
pub struct App {
  /// Some kind of epoch start the application started at.
  start_time: SteadyTime,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
}

impl App {
  pub fn init(kbd: Keyboard, mouse: Mouse, cursor: MouseMove, scroll: Scroll, window: Window) -> Self {
    App {
      start_time: SteadyTime::now(),
      kbd: kbd,
      mouse: mouse,
      cursor: cursor,
      scroll: scroll,
      window: window
    }
  }

  pub fn time(&self) -> f64 {
    (SteadyTime::now() - self.start_time).num_nanoseconds().unwrap() as f64 * 1e-9
  }

  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool
      where H: KeyboardHandler + MouseButtonHandler + CursorHandler + ScrollHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !handler.on_cursor_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  pub fn step<R>(&mut self, fps: Option<u32>, mut draw_frame: R) -> bool where R: FnMut(f64) {
    let loop_start_time = SteadyTime::now();

    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);

    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps {
      let fps = fps as f32;
      let elapsed_time = SteadyTime::now() - loop_start_time;
      let max_time = Duration::nanoseconds((1. / (fps as f64) * 1e9) as i64);

      if elapsed_time > max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(sleep_time.to_std().unwrap());
      }
    }

    true
  }
}

/// Debug handler.
pub struct DebugHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f64; 2]
}

impl DebugHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    DebugHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f64; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx as f32));
    }

    self.last_cursor = cursor;
  }
}

impl KeyboardHandler for DebugHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return false }
    }

    true
  }
}

impl MouseButtonHandler for DebugHandler {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    true
  }
}

impl CursorHandler for DebugHandler {
  fn on_cursor_move(&mut self, dir: [f64; 2]) -> bool {
    self.orient_camera_on_event(dir);
    true
  }
}

impl ScrollHandler for DebugHandler {
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}
<|endoftext|>