<commit_before>// MIT License

// Copyright (c) 2016 Jerome Froelich

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate bit_vec;
extern crate rand;
extern crate siphasher;

use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};

use bit_vec::BitVec;
use siphasher::sip::SipHasher24;

#[derive(Debug)]
pub enum BloomError {
    NoParameterSet,
}

impl fmt::Display for BloomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BloomError::NoParameterSet => {
                write!(f,
                       "Must set either the desired size or false positive ratio to create a \
                        bloom filter")
            }
        }
    }
}

impl Error for BloomError {
    fn description(&self) -> &str {
        match *self {
            BloomError::NoParameterSet => {
                "Must set either the desired size or false positive ratio to create a \
                        bloom filter"
            }
        }
    }
}

#[derive(Debug)]
enum BloomParameter {
    Empty,
    Size(u64), // number of bits in the bloom filter
    FPR(f64), // false positive rate
}

#[derive(Debug)]
pub struct BloomBuilder {
    elements: u64,
    parameter: BloomParameter,
}

impl BloomBuilder {
    pub fn new(elements: u64) -> BloomBuilder {
        BloomBuilder {
            elements: elements,
            parameter: BloomParameter::Empty,
        }
    }

    pub fn with_size(mut self, size: u64) -> BloomBuilder {
        self.parameter = BloomParameter::Size(size);
        self
    }

    pub fn with_fpr(mut self, p: f64) -> BloomBuilder {
        self.parameter = BloomParameter::FPR(p);
        self
    }

    pub fn finish(&self) -> Result<Bloom, BloomError> {
        match self.parameter {
            BloomParameter::Empty => Err(BloomError::NoParameterSet),
            BloomParameter::Size(size) => {
                let hash_count = BloomBuilder::optimal_hash_count(self.elements, size);
                let bloom = Bloom::new(size, hash_count);
                Ok(bloom)
            }
            BloomParameter::FPR(p) => {
                let min_size = BloomBuilder::min_size(self.elements, p);
                let hash_count = BloomBuilder::optimal_hash_count(self.elements, min_size);
                let bloom = Bloom::new(min_size, hash_count);
                Ok(bloom)
            }
        }
    }

    fn min_size(num_elements: u64, p: f64) -> u64 {
        let n = num_elements as f64;
        // m = -1 * n * ln(p) / (ln(2) ^ 2)
        let m = -1f64 * n * p.ln() / (2f64.ln().powf(2f64));
        m.ceil() as u64
    }

    fn optimal_hash_count(num_elements: u64, num_bits: u64) -> u32 {
        let m = num_bits as f64;
        let n = num_elements as f64;
        // k = ln(2) * m / n
        let k = 2f64.ln() * m / n;
        k.ceil() as u32
    }
}

#[derive(Debug)]
pub struct Bloom {
    bits: BitVec,

    // the number of hash functions to compute when inserting and looking up elements
    k: u32,

    // we only need two independent hash functions because we can use double hashing to
    // create new independent hash functions from those two
    hashers: [SipHasher24; 2],
}

impl Bloom {
    fn new(size: u64, k: u32) -> Self {

        Bloom {
            bits: BitVec::from_elem(size as usize, false),
            k: k,
            hashers: [Bloom::get_hasher(), Bloom::get_hasher()],
        }
    }

    fn get_hasher() -> SipHasher24 {
        let mut rng = rand::thread_rng();
        SipHasher24::new_with_keys(rand::Rand::rand(&mut rng), rand::Rand::rand(&mut rng))
    }

    pub fn insert<T>(&mut self, key: T)
        where T: Hash
    {
        // we need to save the results of the first two hashes for when we need to get more
        // than two hashes since we use double hashing uses those hashes to compute further hashes
        let mut hashes = [0u64, 0u64];
        for i in 0..self.k {
            let index = self.get_hash(&mut hashes, &key, i) % self.bits.len();
            self.bits.set(index, true);
        }
    }

    pub fn lookup<T>(&self, item: T) -> bool
        where T: Hash
    {
        let mut hashes = [0u64, 0u64];
        for i in 0..self.k {
            let index = self.get_hash(&mut hashes, &item, i) % self.bits.len();
            if !self.bits[index] {
                return false;
            }
        }

        true
    }

    pub fn lookup_and_insert<T>(&mut self, key: T) -> bool
        where T: Hash
    {
        let mut hashes = [0u64, 0u64];
        let mut found = true;
        for i in 0..self.k {
            let index = self.get_hash(&mut hashes, &key, i) % self.bits.len();
            if !self.bits[index] {
                found = false;
                self.bits.set(index, true);
            }
        }

        found
    }

    fn get_hash<T>(&self, hashes: &mut [u64; 2], key: &T, i: u32) -> usize
        where T: Hash
    {
        if i < 2 {
            let hasher = &mut self.hashers[i as usize].clone();
            key.hash(hasher);
            let hash = hasher.finish();
            hashes[i as usize] = hash;
            hash as usize
        } else {
            // use double hashing to get any additional hashes
            hashes[0]
                .wrapping_add((i as u64).wrapping_mul(hashes[1]) %
                              self.bits.len() as u64) as usize
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Bloom, BloomBuilder};

    #[test]
    fn test_with_size() {
        let size = 2u64.pow(20);
        let b = BloomBuilder::new(size / 2).with_size(size).finish().unwrap();
        assert_eq!(b.bits.len() as u64, size);
        assert_eq!(b.k, 2);
    }

    #[test]
    fn test_with_fpr() {
        let elements = 2u64.pow(20);
        let fpr = 0.01;
        let b = BloomBuilder::new(elements).with_fpr(fpr).finish().unwrap();
        println!("{:?}", b.bits.len());
        assert_eq!(b.k, 7);
    }

    #[test]
    fn test_operations() {
        let elements = 2u64.pow(20);
        let fpr = 0.01;
        let mut b = BloomBuilder::new(elements).with_fpr(fpr).finish().unwrap();

        assert!(!b.lookup(3));
        assert!(!b.lookup(23));
        assert!(!b.lookup(51));

        b.insert(3);
        b.insert(23);
        b.insert(51);

        assert!(b.lookup(3));
        assert!(b.lookup(23));
        assert!(b.lookup(51));

        assert!(b.lookup_and_insert(3));
        assert!(b.lookup_and_insert(23));
        assert!(b.lookup_and_insert(51));
    }
}
<commit_msg>Make Bloom generic over a single type<commit_after>// MIT License

// Copyright (c) 2016 Jerome Froelich

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! An implementation of a bloom filter as as described in
//! [Space/Time Trade-offs in Hash Coding with Allowable Errors] (http://dmod.eu/deca/ft_gateway.cfm.pdf).
//!
//! ## Example
//!
//! ``` rust,no_run
//!
//! fn main() {
//! }
//! ```

extern crate bit_vec;
extern crate rand;
extern crate siphasher;

use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;

use bit_vec::BitVec;
use siphasher::sip::SipHasher24;

#[derive(Debug)]
pub enum BloomError {
    NoParameterSet,
}

impl fmt::Display for BloomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BloomError::NoParameterSet => {
                write!(f,
                       "Must set either the desired size or false positive ratio to create a \
                        bloom filter")
            }
        }
    }
}

impl Error for BloomError {
    fn description(&self) -> &str {
        match *self {
            BloomError::NoParameterSet => {
                "Must set either the desired size or false positive ratio to create a \
                        bloom filter"
            }
        }
    }
}

#[derive(Debug)]
enum BloomParameter {
    Empty,
    Size(u64), // number of bits in the bloom filter
    FPR(f64), // false positive rate
}

#[derive(Debug)]
pub struct BloomBuilder {
    elements: u64,
    parameter: BloomParameter,
}

impl BloomBuilder {
    pub fn new(elements: u64) -> BloomBuilder {
        BloomBuilder {
            elements: elements,
            parameter: BloomParameter::Empty,
        }
    }

    pub fn with_size(mut self, size: u64) -> BloomBuilder {
        self.parameter = BloomParameter::Size(size);
        self
    }

    pub fn with_fpr(mut self, p: f64) -> BloomBuilder {
        self.parameter = BloomParameter::FPR(p);
        self
    }

    pub fn finish<T>(&self) -> Result<Bloom<T>, BloomError>
        where T: Hash
    {
        match self.parameter {
            BloomParameter::Empty => Err(BloomError::NoParameterSet),
            BloomParameter::Size(size) => {
                let hash_count = BloomBuilder::optimal_hash_count(self.elements, size);
                let bloom = Bloom::new(size, hash_count);
                Ok(bloom)
            }
            BloomParameter::FPR(p) => {
                let min_size = BloomBuilder::min_size(self.elements, p);
                let hash_count = BloomBuilder::optimal_hash_count(self.elements, min_size);
                let bloom: Bloom<T> = Bloom::new(min_size, hash_count);
                Ok(bloom)
            }
        }
    }

    fn min_size(num_elements: u64, p: f64) -> u64 {
        let n = num_elements as f64;
        // m = -1 * n * ln(p) / (ln(2) ^ 2)
        let m = -1f64 * n * p.ln() / (2f64.ln().powf(2f64));
        m.ceil() as u64
    }

    fn optimal_hash_count(num_elements: u64, num_bits: u64) -> u32 {
        let m = num_bits as f64;
        let n = num_elements as f64;
        // k = ln(2) * m / n
        let k = 2f64.ln() * m / n;
        k.ceil() as u32
    }
}

#[derive(Debug)]
pub struct Bloom<T: Hash> {
    bits: BitVec,

    // the number of hash functions to compute when inserting and looking up elements
    k: u32,

    // we only need two independent hash functions because we can use double hashing to
    // create new independent hash functions from those two
    hashers: [SipHasher24; 2],

    marker: PhantomData<T>,
}

impl<T: Hash> Bloom<T> {
    fn new(size: u64, k: u32) -> Self {

        Bloom {
            bits: BitVec::from_elem(size as usize, false),
            k: k,
            hashers: [Bloom::<T>::get_hasher(), Bloom::<T>::get_hasher()],
            marker: PhantomData,
        }
    }

    fn get_hasher() -> SipHasher24 {
        let mut rng = rand::thread_rng();
        SipHasher24::new_with_keys(rand::Rand::rand(&mut rng), rand::Rand::rand(&mut rng))
    }

    pub fn insert(&mut self, key: T) {
        // we need to save the results of the first two hashes for when we need to get more
        // than two hashes since we use double hashing uses those hashes to compute further hashes
        let mut hashes = [0u64, 0u64];
        for i in 0..self.k {
            let index = self.get_hash(&mut hashes, &key, i) % self.bits.len();
            self.bits.set(index, true);
        }
    }

    pub fn lookup(&self, item: T) -> bool {
        let mut hashes = [0u64, 0u64];
        for i in 0..self.k {
            let index = self.get_hash(&mut hashes, &item, i) % self.bits.len();
            if !self.bits[index] {
                return false;
            }
        }

        true
    }

    pub fn lookup_and_insert(&mut self, key: T) -> bool {
        let mut hashes = [0u64, 0u64];
        let mut found = true;
        for i in 0..self.k {
            let index = self.get_hash(&mut hashes, &key, i) % self.bits.len();
            if !self.bits[index] {
                found = false;
                self.bits.set(index, true);
            }
        }

        found
    }

    fn get_hash(&self, hashes: &mut [u64; 2], key: &T, i: u32) -> usize {
        if i < 2 {
            let hasher = &mut self.hashers[i as usize].clone();
            key.hash(hasher);
            let hash = hasher.finish();
            hashes[i as usize] = hash;
            hash as usize
        } else {
            // use double hashing to get any additional hashes
            hashes[0]
                .wrapping_add((i as u64).wrapping_mul(hashes[1]) %
                              self.bits.len() as u64) as usize
        }
    }
}

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

    #[test]
    fn test_with_size() {
        let size = 2u64.pow(20);
        let b = BloomBuilder::new(size / 2).with_size(size).finish::<i64>().unwrap();
        assert_eq!(b.bits.len() as u64, size);
        assert_eq!(b.k, 2);
    }

    #[test]
    fn test_with_fpr() {
        let elements = 2u64.pow(20);
        let fpr = 0.01;
        let b = BloomBuilder::new(elements).with_fpr(fpr).finish::<i64>().unwrap();
        println!("{:?}", b.bits.len());
        assert_eq!(b.k, 7);
    }

    #[test]
    fn test_operations() {
        let elements = 2u64.pow(20);
        let fpr = 0.01;
        let mut b = BloomBuilder::new(elements).with_fpr(fpr).finish::<i64>().unwrap();

        assert!(!b.lookup(3));
        assert!(!b.lookup(23));
        assert!(!b.lookup(51));

        b.insert(3);
        b.insert(23);
        b.insert(51);

        assert!(b.lookup(3));
        assert!(b.lookup(23));
        assert!(b.lookup(51));

        assert!(b.lookup_and_insert(3));
        assert!(b.lookup_and_insert(23));
        assert!(b.lookup_and_insert(51));
    }
}
<|endoftext|>


<commit_before>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

// Use Horners method to evaluate polynomials at `x0`
macro_rules! eval_poly {
    ( $x0:expr; $( $p:expr ),* ) => {
        {
            let mut coefs = vec![$($p,)*];
            coefs.reverse();
            let mut sum = 0.0;
            for c in coefs.iter() {
                sum = sum * $x0 + c;
            }
            sum
        }
    }
}

/// Compute the real valued digamma function. `d/dx ln Gamma(x)`.
/// Appriximation based on Beal, Matthew J. (2003). *Variational
/// Algorithms for Approximate Bayesian Inference* (PhD thesis). The
/// Gatsby Computational Neuroscience Unit, University College
/// London. pp. 265–266
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
#[inline]
pub fn digamma(x: f64)-> f64 {
    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x.powi(2);
        x.ln() - 0.5*inv_x - inv_x_e2 * eval_poly!(
            inv_x_e2;
            // Coefficients are `Bernoulli[2n] / 2n`
            1.0/12.0, -1.0/120.0, 1.0/252.0, -1.0/240.0,
            5.0/660.0, -691.0/32760.0, 1.0/12.0, -3617.0/8160.0
        )
    } else {
        // Shift by recurrence
        digamma(x + 1.0) - x.recip()
    }
}

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

    #[test]
    fn test_digamma() {
        use std::f64::consts::{ FRAC_PI_2, LN_2 };
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, digamma(0.25));
    }
}
<commit_msg>Detail the description of digamma<commit_after>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

// Use Horners method to evaluate polynomials at `x0`
macro_rules! eval_poly {
    ( $x0:expr; $( $p:expr ),* ) => {
        {
            let mut coefs = vec![$($p,)*];
            coefs.reverse();
            let mut sum = 0.0;
            for c in coefs.iter() {
                sum = sum * $x0 + c;
            }
            sum
        }
    }
}

/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// * M. J. Beal, “Variational Algorithms for Approximate Bayesian Inference.”
/// The Gatsby Computational Neuroscience Unit, University College London, 2003,
/// pp. 265–266.
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
#[inline]
pub fn digamma(x: f64)-> f64 {
    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x.powi(2);
        x.ln() - 0.5*inv_x - inv_x_e2 * eval_poly!(
            inv_x_e2;
            // Coefficients are `Bernoulli[2n] / 2n`
            1.0/12.0, -1.0/120.0, 1.0/252.0, -1.0/240.0,
            5.0/660.0, -691.0/32760.0, 1.0/12.0, -3617.0/8160.0
        )
    } else {
        // Shift by recurrence
        digamma(x + 1.0) - x.recip()
    }
}

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

    #[test]
    fn test_digamma() {
        use std::f64::consts::{ FRAC_PI_2, LN_2 };
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, digamma(0.25));
    }
}
<|endoftext|>


<commit_before>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     }).detach();
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

#[cfg(test)] extern crate std;
extern crate core;

use core::atomic::{AtomicBool, Ordering, INIT_ATOMIC_BOOL};
use core::cell::UnsafeCell;
use core::kinds::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, INIT_STATIC_SPINLOCK};
///
/// static SPLCK: StaticSpinlock = INIT_STATIC_SPINLOCK;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = Spinlock {
    lock: INIT_ATOMIC_BOOL,
    data: UnsafeCell { value: () },
};

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: INIT_ATOMIC_BOOL,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<commit_msg>INIT_ATOMIC_BOOL -> ATOMIC_BOOL_INIT<commit_after>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     }).detach();
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

#[cfg(test)] extern crate std;
extern crate core;

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::kinds::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, INIT_STATIC_SPINLOCK};
///
/// static SPLCK: StaticSpinlock = INIT_STATIC_SPINLOCK;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>extern crate libloading;
#[macro_use]
extern crate lazy_static;

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ffi;

use std::ffi::{CString, CStr};
use std::ptr;
use libloading::Library;

use ffi::{
    IVRCompositor,
    IVRSystem,
    IVRChaperone,
    IVRCompositor_FnTable,
    IVRSystem_FnTable,
    // IVRChaperone_FnTable,
};

pub use ffi::{
    Texture,
    TrackedDevicePose,
    HmdMatrix34,
    HmdMatrix44,
    EVREye as Eye,
    EVRInitError as InitError,
    EVRApplicationType as ApplicationType,
    EGraphicsAPIConvention as GraphicsAPIConvention,
    EVRSubmitFlags as SubmitFlags,
    EVRCompositorError as CompositorError,
    ETrackingUniverseOrigin as TrackingUniverseOrigin,
    EColorSpace as ColorSpace,
    VRTextureBounds as TextureBounds,
    ETrackedDeviceClass as TrackedDeviceClass,
    ETrackedControllerRole as TrackedControllerRole,
    k_unMaxTrackedDeviceCount as MAX_TRACKED_DEVICE_COUNT
};

#[allow(non_snake_case)]
#[allow(dead_code)]
struct ApiFunctions {
    VR_InitInternal:            extern fn (peError: *mut InitError, eType: ApplicationType) -> usize,
    VR_ShutdownInternal:        extern fn (),
    VR_IsHmdPresent:            extern fn () -> ::std::os::raw::c_char,
    VR_GetStringForHmdError:    extern fn (error: InitError) -> *mut ::std::os::raw::c_char,
    VR_GetGenericInterface:     extern fn (pchInterfaceVersion: *const ::std::os::raw::c_char, peError: *mut InitError) -> usize,
    VR_IsRuntimeInstalled:      extern fn () -> ::std::os::raw::c_char,
    VR_GetVRInitErrorAsSymbol:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    VR_GetVRInitErrorAsEnglishDescription:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    lib: Library,
}

unsafe impl Sync for ApiFunctions {}

lazy_static! {
    static ref API: ApiFunctions = {
        let lib = Library::new("openvr_api.dll").unwrap();

        unsafe {
            ApiFunctions {
                VR_InitInternal:            *lib.get(b"VR_InitInternal\0").unwrap(),
                VR_ShutdownInternal:        *lib.get(b"VR_ShutdownInternal\0").unwrap(),
                VR_IsHmdPresent:            *lib.get(b"VR_IsHmdPresent\0").unwrap(),
                VR_GetStringForHmdError:    *lib.get(b"VR_GetStringForHmdError\0").unwrap(),
                VR_GetGenericInterface:     *lib.get(b"VR_GetGenericInterface\0").unwrap(),
                VR_IsRuntimeInstalled:      *lib.get(b"VR_IsRuntimeInstalled\0").unwrap(),
                VR_GetVRInitErrorAsSymbol:  *lib.get(b"VR_GetVRInitErrorAsSymbol\0").unwrap(),
                VR_GetVRInitErrorAsEnglishDescription: *lib.get(b"VR_GetVRInitErrorAsEnglishDescription\0").unwrap(),
                lib: lib,
            }
        }
    };
}

pub struct VRCompositor {
    i: *mut IVRCompositor
}

impl VRCompositor {
    fn new(vr_compositor: *mut IVRCompositor) -> Self {
        assert!(vr_compositor as *const _ != ptr::null());
        VRCompositor {
            i:  vr_compositor
        }
    }

    /// Updated scene texture to display. If bounds is NULL the entire texture will be used.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::Submit
    pub fn submit(
        &mut self,
        eye:            Eye,
        texture:        *mut Texture,
        bounds:         *mut TextureBounds,
        submit_flags:   SubmitFlags
    ) -> CompositorError {
        unsafe {
            ((*self.i).Submit)(eye, texture, bounds, submit_flags)
        }
    }

    /// Returns pose(s) to use to render scene.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::WaitGetPoses
    pub fn wait_get_poses(
        &mut self,
    ) -> [TrackedDevicePose; ffi::k_unMaxTrackedDeviceCount as usize] {
        unsafe {
            let mut render_poses = [TrackedDevicePose::default(); ffi::k_unMaxTrackedDeviceCount as usize];
            ((*self.i).WaitGetPoses)(
                (&mut render_poses[..]).as_mut_ptr(),
                render_poses.len() as u32,
                std::ptr::null_mut(),
                0
            );

            render_poses
        }
    }
}

pub struct VRChaperone {
    _i: *mut IVRChaperone
}

pub struct VRSystem {
    i: *mut IVRSystem
}

impl VRSystem {
    fn new(vr_system: *mut IVRSystem) -> Self {
        assert!(vr_system as *const _ != ptr::null());
        VRSystem {
            i:  vr_system
        }
    }

    /// Provides the game with the minimum size that it should use for its offscreen render
    /// target to minimize pixel stretching. This size is matched with the projection matrix
    // and distortion function and will change from display to display depending on resolution,
    // distortion, and field of view.
    pub fn get_recommended_render_target_size(&self) -> (u32, u32) {
        unsafe {
            let mut width = 0;
            let mut height = 0;
            ((*self.i).GetRecommendedRenderTargetSize)(&mut width, &mut height);
            (width, height)
        }
    }

    /// Returns the projection matrix to use for the specified eye.
    pub fn get_projection_matrix(
        &self,
        eye:                Eye,
        near_z:             f32,
        far_z:              f32,
        api:                GraphicsAPIConvention
    ) -> HmdMatrix44 {
        unsafe {
            ((*self.i).GetProjectionMatrix)(
                eye,
                near_z,
                far_z,
                api
            )
        }
    }

    /// Returns the transform between the view space and eye space.
    pub fn get_eye_to_head_transform(&self, eye: Eye) -> HmdMatrix34 {
        unsafe {
            ((*self.i).GetEyeToHeadTransform)(eye)
        }
    }

    /// Calculates updated poses for all devices.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
    pub fn get_device_to_absolute_tracking_pose(
        &self,
        origin: TrackingUniverseOrigin,
        predicted_seconds_to_photons_from_now:  f32,
        tracked_device_pose_array: &mut [TrackedDevicePose]
    ) {
        unsafe {
            ((*self.i).GetDeviceToAbsoluteTrackingPose)(
                origin,
                predicted_seconds_to_photons_from_now,
                tracked_device_pose_array.as_mut_ptr(),
                tracked_device_pose_array.len() as u32
            )
        }
    }

    pub fn reset_seated_zero_pose(&self) {
        unsafe {
            ((*self.i).ResetSeatedZeroPose)()
        }
    }

    pub fn get_tracked_device_class(&self, device_index: usize) -> TrackedDeviceClass {
        unsafe {
            ((*self.i).GetTrackedDeviceClass)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_role_for_tracked_device_index(&self, device_index: usize) -> TrackedControllerRole {
        unsafe {
            ((*self.i).GetControllerRoleForTrackedDeviceIndex)(device_index as ffi::TrackedDeviceIndex)
        }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let err = CStr::from_ptr((API.VR_GetVRInitErrorAsEnglishDescription)(*self));
            write!(f, "{}", err.to_string_lossy())
        }
    }
}

impl std::error::Error for InitError {
    fn description(&self) -> &str {
        "init error"
    }
}

pub struct VRContext {
    pub system:     VRSystem,
    pub compositor: VRCompositor,

    // chaperone:         VRChaperone,
    // chaperone_setup:    IVRChaperoneSetup,
    // overlay:            IVROverlay,
    // render_models:      IVRRenderModels,
    // IVRExtendedDisplay: *mut IVRExtendedDisplay,
    // IVRSettings: *mut IVRSettings,
    // IVRApplications: *mut IVRApplications,
}

impl Drop for VRContext {
    fn drop(&mut self) {
        // VR_ShutdownInternal();
    }
}

pub fn initialize() -> Result<VRContext, InitError> {
    let mut err = InitError::None;
    let _hmd = (API.VR_InitInternal)(&mut err, ApplicationType::VRApplication_Scene);
    if err != InitError::None {
        Err(err)
    } else {

        let system = (API.VR_GetGenericInterface)(CString::new(IVRSystem_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRSystem;
        if err != InitError::None {
            return Err(err);
        }
        let system = VRSystem::new(system);

        let compositor = (API.VR_GetGenericInterface)(CString::new(IVRCompositor_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRCompositor;
        if err != InitError::None {
            return Err(err);
        }
        let compositor = VRCompositor::new(compositor);

        Ok(VRContext {
            system:     system,
            compositor: compositor
        })
    }
}

/// Returns true if the system believes that an HMD is present on the system.
pub fn is_hmd_present() -> bool {
    (API.VR_IsHmdPresent)() != 0
}

/// Returns true if the SteamVR runtime is installed.
pub fn is_runtime_installed() -> bool {
    (API.VR_IsRuntimeInstalled)() != 0
}

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

    #[test]
    fn runtime_installed() {
        assert!(is_runtime_installed());
    }

    #[test]
    fn hmd_present() {
        assert!(is_hmd_present());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    #[test]
    fn vr_init() {
        // NOTE: initializing seems to fail if a window has not been created

        // match init() {
        //     Err(err) => {
        //         println!("init failed: {} - {}", err, err.description());
        //         assert!(false);
        //     }
        //     Ok(context) => {
        //         context.system.get_recommended_render_target_size();
        //     }
        // }
    }
}
<commit_msg>stubbing out VRRenderModels <commit_after>extern crate libloading;
#[macro_use]
extern crate lazy_static;

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ffi;

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};
use std::ptr;
use std::mem;
use libloading::Library;

use ffi::{
    IVRCompositor,
    IVRSystem,
    IVRChaperone,
    IVRRenderModels,
    IVRCompositor_FnTable,
    IVRSystem_FnTable,
    // IVRChaperone_FnTable,
};

pub use ffi::{
    Texture,
    TextureID,
    TrackedDevicePose,
    HmdMatrix34,
    HmdMatrix44,
    EVREye as Eye,
    EVRInitError as InitError,
    EVRApplicationType as ApplicationType,
    EGraphicsAPIConvention as GraphicsAPIConvention,
    EVRSubmitFlags as SubmitFlags,
    EVRCompositorError as CompositorError,
    ETrackingUniverseOrigin as TrackingUniverseOrigin,
    EColorSpace as ColorSpace,
    VRTextureBounds as TextureBounds,
    ETrackedDeviceClass as TrackedDeviceClass,
    ETrackedControllerRole as TrackedControllerRole,
    EVRRenderModelError as RenderModelError,
    k_unMaxTrackedDeviceCount as MAX_TRACKED_DEVICE_COUNT
};

#[allow(non_snake_case)]
#[allow(dead_code)]
struct ApiFunctions {
    VR_InitInternal:            extern fn (peError: *mut InitError, eType: ApplicationType) -> usize,
    VR_ShutdownInternal:        extern fn (),
    VR_IsHmdPresent:            extern fn () -> ::std::os::raw::c_char,
    VR_GetStringForHmdError:    extern fn (error: InitError) -> *mut ::std::os::raw::c_char,
    VR_GetGenericInterface:     extern fn (pchInterfaceVersion: *const ::std::os::raw::c_char, peError: *mut InitError) -> usize,
    VR_IsRuntimeInstalled:      extern fn () -> ::std::os::raw::c_char,
    VR_GetVRInitErrorAsSymbol:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    VR_GetVRInitErrorAsEnglishDescription:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    lib: Library,
}

unsafe impl Sync for ApiFunctions {}

lazy_static! {
    static ref API: ApiFunctions = {
        let lib = Library::new("openvr_api.dll").unwrap();

        unsafe {
            ApiFunctions {
                VR_InitInternal:            *lib.get(b"VR_InitInternal\0").unwrap(),
                VR_ShutdownInternal:        *lib.get(b"VR_ShutdownInternal\0").unwrap(),
                VR_IsHmdPresent:            *lib.get(b"VR_IsHmdPresent\0").unwrap(),
                VR_GetStringForHmdError:    *lib.get(b"VR_GetStringForHmdError\0").unwrap(),
                VR_GetGenericInterface:     *lib.get(b"VR_GetGenericInterface\0").unwrap(),
                VR_IsRuntimeInstalled:      *lib.get(b"VR_IsRuntimeInstalled\0").unwrap(),
                VR_GetVRInitErrorAsSymbol:  *lib.get(b"VR_GetVRInitErrorAsSymbol\0").unwrap(),
                VR_GetVRInitErrorAsEnglishDescription: *lib.get(b"VR_GetVRInitErrorAsEnglishDescription\0").unwrap(),
                lib: lib,
            }
        }
    };
}

pub struct VRCompositor {
    i: *mut IVRCompositor
}

impl VRCompositor {
    fn new(vr_compositor: *mut IVRCompositor) -> Self {
        assert!(vr_compositor as *const _ != ptr::null());
        VRCompositor {
            i:  vr_compositor
        }
    }

    /// Updated scene texture to display. If bounds is NULL the entire texture will be used.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::Submit
    pub fn submit(
        &mut self,
        eye:            Eye,
        texture:        *mut Texture,
        bounds:         *mut TextureBounds,
        submit_flags:   SubmitFlags
    ) -> CompositorError {
        unsafe {
            ((*self.i).Submit)(eye, texture, bounds, submit_flags)
        }
    }

    /// Returns pose(s) to use to render scene.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::WaitGetPoses
    pub fn wait_get_poses(
        &mut self,
    ) -> [TrackedDevicePose; ffi::k_unMaxTrackedDeviceCount as usize] {
        unsafe {
            let mut render_poses = [TrackedDevicePose::default(); ffi::k_unMaxTrackedDeviceCount as usize];
            ((*self.i).WaitGetPoses)(
                (&mut render_poses[..]).as_mut_ptr(),
                render_poses.len() as u32,
                std::ptr::null_mut(),
                0
            );

            render_poses
        }
    }
}

pub struct VRChaperone {
    _i: *mut IVRChaperone
}

pub struct RenderModel {
}

pub struct VRRenderModels {
    i: *mut IVRRenderModels
}

impl VRRenderModels {
    pub fn load_render_model_async(
        &mut self,
        render_model_name: *const c_char
    ) -> Result<ffi::RenderModel, RenderModelError> {
        unsafe {
            let render_model: *mut *mut ffi::RenderModel = mem::zeroed();
            let error = ((*self.i).LoadRenderModel_Async)(render_model_name, render_model);
            if error == RenderModelError::None {
                Ok(**render_model)
            } else {
                Err(error)
            }
        }
    }

    pub fn free_render_model(&mut self, render_model: &mut ffi::RenderModel) {
        unsafe {
            ((*self.i).FreeRenderModel)(render_model)
        }
    }

    pub fn load_texture_async(
        &mut self,
        texture_id: TextureID
    ) -> Result<ffi::RenderModel_TextureMap, RenderModelError> {
        unsafe {
            let texture: *mut *mut ffi::RenderModel_TextureMap = mem::zeroed();
            let error = ((*self.i).LoadTexture_Async)(texture_id, texture);
            if error == RenderModelError::None {
                Ok(**texture)
            } else {
                Err(error)
            }
        }
    }

    pub fn free_texture(&mut self, texture: &mut ffi::RenderModel_TextureMap) {
        unsafe {
            ((*self.i).FreeTexture)(texture)
        }
    }
}

pub struct VRSystem {
    i: *mut IVRSystem
}

impl VRSystem {
    fn new(vr_system: *mut IVRSystem) -> Self {
        assert!(vr_system as *const _ != ptr::null());
        VRSystem {
            i:  vr_system
        }
    }

    /// Provides the game with the minimum size that it should use for its offscreen render
    /// target to minimize pixel stretching. This size is matched with the projection matrix
    // and distortion function and will change from display to display depending on resolution,
    // distortion, and field of view.
    pub fn get_recommended_render_target_size(&self) -> (u32, u32) {
        unsafe {
            let mut width = 0;
            let mut height = 0;
            ((*self.i).GetRecommendedRenderTargetSize)(&mut width, &mut height);
            (width, height)
        }
    }

    /// Returns the projection matrix to use for the specified eye.
    pub fn get_projection_matrix(
        &self,
        eye:                Eye,
        near_z:             f32,
        far_z:              f32,
        api:                GraphicsAPIConvention
    ) -> HmdMatrix44 {
        unsafe {
            ((*self.i).GetProjectionMatrix)(
                eye,
                near_z,
                far_z,
                api
            )
        }
    }

    /// Returns the transform between the view space and eye space.
    pub fn get_eye_to_head_transform(&self, eye: Eye) -> HmdMatrix34 {
        unsafe {
            ((*self.i).GetEyeToHeadTransform)(eye)
        }
    }

    /// Calculates updated poses for all devices.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
    pub fn get_device_to_absolute_tracking_pose(
        &self,
        origin: TrackingUniverseOrigin,
        predicted_seconds_to_photons_from_now:  f32,
        tracked_device_pose_array: &mut [TrackedDevicePose]
    ) {
        unsafe {
            ((*self.i).GetDeviceToAbsoluteTrackingPose)(
                origin,
                predicted_seconds_to_photons_from_now,
                tracked_device_pose_array.as_mut_ptr(),
                tracked_device_pose_array.len() as u32
            )
        }
    }

    pub fn reset_seated_zero_pose(&self) {
        unsafe {
            ((*self.i).ResetSeatedZeroPose)()
        }
    }

    pub fn get_tracked_device_class(&self, device_index: usize) -> TrackedDeviceClass {
        unsafe {
            ((*self.i).GetTrackedDeviceClass)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_role_for_tracked_device_index(&self, device_index: usize) -> TrackedControllerRole {
        unsafe {
            ((*self.i).GetControllerRoleForTrackedDeviceIndex)(device_index as ffi::TrackedDeviceIndex)
        }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let err = CStr::from_ptr((API.VR_GetVRInitErrorAsEnglishDescription)(*self));
            write!(f, "{}", err.to_string_lossy())
        }
    }
}

impl std::error::Error for InitError {
    fn description(&self) -> &str {
        "init error"
    }
}

pub struct VRContext {
    pub system:     VRSystem,
    pub compositor: VRCompositor,

    // chaperone:         VRChaperone,
    // chaperone_setup:    IVRChaperoneSetup,
    // overlay:            IVROverlay,
    // render_models:      IVRRenderModels,
    // IVRExtendedDisplay: *mut IVRExtendedDisplay,
    // IVRSettings: *mut IVRSettings,
    // IVRApplications: *mut IVRApplications,
}

impl Drop for VRContext {
    fn drop(&mut self) {
        // VR_ShutdownInternal();
    }
}

pub fn initialize() -> Result<VRContext, InitError> {
    let mut err = InitError::None;
    let _hmd = (API.VR_InitInternal)(&mut err, ApplicationType::VRApplication_Scene);
    if err != InitError::None {
        Err(err)
    } else {

        let system = (API.VR_GetGenericInterface)(CString::new(IVRSystem_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRSystem;
        if err != InitError::None {
            return Err(err);
        }
        let system = VRSystem::new(system);

        let compositor = (API.VR_GetGenericInterface)(CString::new(IVRCompositor_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRCompositor;
        if err != InitError::None {
            return Err(err);
        }
        let compositor = VRCompositor::new(compositor);

        Ok(VRContext {
            system:     system,
            compositor: compositor
        })
    }
}

/// Returns true if the system believes that an HMD is present on the system.
pub fn is_hmd_present() -> bool {
    (API.VR_IsHmdPresent)() != 0
}

/// Returns true if the SteamVR runtime is installed.
pub fn is_runtime_installed() -> bool {
    (API.VR_IsRuntimeInstalled)() != 0
}

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

    #[test]
    fn runtime_installed() {
        assert!(is_runtime_installed());
    }

    #[test]
    fn hmd_present() {
        assert!(is_hmd_present());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    #[test]
    fn vr_init() {
        // NOTE: initializing seems to fail if a window has not been created

        // match init() {
        //     Err(err) => {
        //         println!("init failed: {} - {}", err, err.description());
        //         assert!(false);
        //     }
        //     Ok(context) => {
        //         context.system.get_recommended_render_target_size();
        //     }
        // }
    }
}
<|endoftext|>


<commit_before>// #get
// #set
// #peek
// #new
// #clear
//has
use std::collections::HashMap;

// Doubly linked list
struct Node <V> {
    prev: Option<Box<Node<V>>>,
    next: Option<Box<Node<V>>>,
    val: V,
}

pub struct LRU <K, V> {
    cache: HashMap<K, V>,
    head: Option<Node<V>>,
    tail: Option<Node<V>>,
    len: u16,
}

impl <K: Eq + std::hash::Hash, V> LRU <K, V> {
    pub fn new() -> LRU<K, V> {
        LRU {
            cache: HashMap::new(),
            head: None,
            tail: None,
            len: 0
        }
    }
    pub fn set(&mut self, key: K, val: V) -> &mut LRU<K, V>{
        use std::collections::hash_map::Entry;
        if let Some(node) = self.cache.get(&key) {
            // remove node from linked list, and replace at head
            self
        } else {
            let addition = Node {
                prev: None,
                // wrap it in a layer of indirection if exists.
                next: self.head.map(|x| Box::new(x)),
                val: val
            };
            self.head = Some(addition);
            self
        }
    }
}

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

    #[test]
    fn lru_instantiaion() {
        let lru: LRU<&str, u8> = LRU::new();
    }

    // #[test]
}
<commit_msg>begins experimenting with "entry" hashmap method<commit_after>// #get
// #set
// #peek
// #new
// #clear
//has
use std::collections::HashMap;

// Doubly linked list
struct Node <V> {
    prev: Option<Box<Node<V>>>,
    next: Option<Box<Node<V>>>,
    val: V,
}

pub struct LRU <K, V> {
    cache: HashMap<K, V>,
    head: Option<Node<V>>,
    tail: Option<Node<V>>,
    len: u16,
}

impl <K: Eq + std::hash::Hash, V> LRU <K, V> {
    pub fn new() -> LRU<K, V> {
        LRU {
            cache: HashMap::new(),
            head: None,
            tail: None,
            len: 0
        }
    }
    pub fn set(&mut self, key: K, val: V) -> &mut LRU<K, V>{
        use std::collections::hash_map::Entry;

        match self.cache.entry(&key) {
            Entry::Occupied(_, val) => {},
            Entry::Vacant(_) => {}
        }
    }
}

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

    #[test]
    fn lru_instantiaion() {
        let lru: LRU<&str, u8> = LRU::new();
    }

    // #[test]
}
<|endoftext|>


<commit_before>#![feature(convert, from_raw_os, collections)]
#![cfg_attr(windows, feature(fs_ext))]
//! Securely create and manage temporary files. Temporary files created by this create are
//! automatically deleted.
extern crate libc;
extern crate rand;

use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error;
use std::fmt;
use std::env;

mod imp;
mod util;

/// An unnamed temporary file.
///
/// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
///
/// Deletion:
///
/// Linux >= 3.11: The temporary file is never linked into the filesystem so it can't be leaked.
///
/// Other *nix: The temporary file is immediately unlinked on create. The OS will delete it when
/// the last open copy of it is closed (the last TempFile reference to it is dropped).
///
/// Windows: The temporary file is marked DeleteOnClose and, again, will be deleted when the last
/// open copy of it is closed. Unlike *nix operating systems, the file is not immediately unlinked
/// from the filesystem.
pub struct TempFile(File);

impl TempFile {
    /// Create a new temporary file.
    #[inline(always)]
    pub fn new() -> io::Result<TempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    #[inline(always)]
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<TempFile> {
        imp::create(dir.as_ref()).map(|f| TempFile(f))
    }

    /// Create a new temporary file and open it `count` times returning `count` independent
    /// references to the same file.
    ///
    /// This can be useful if you want multiple seek positions in the same temporary file.
    /// Additionally, this function guarantees that all of the returned temporary file objects
    /// refer to the same underlying temporary file even in the presence of a pathological
    /// temporary file cleaner.
    #[inline(always)]
    pub fn shared(count: usize) -> io::Result<Vec<TempFile>> {
        Self::shared_in(&env::temp_dir(), count)
    }

    /// Same as `shared` but creates the file in the specified directory.
    #[inline(always)]
    pub fn shared_in<P: AsRef<Path>>(dir: P, count: usize) -> io::Result<Vec<TempFile>> {
        imp::create_shared(dir.as_ref(), count).map(|files| files.map_in_place(|f|TempFile(f)))
    }

    /// Number of bytes in the file.
    #[inline(always)]
    pub fn len(&self) -> io::Result<u64> {
        self.0.metadata().map(|m| m.len())
    }

    /// Truncate the file to `size` bytes.
    #[inline(always)]
    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.0.set_len(size)
    }

    /// Re-open the temporary file. The returned TempFile will refer to the same underlying
    /// temporary file but will have an independent offset.
    ///
    /// This method is only available on windows and Linux, not FreeBSD/MacOS. Unfortunately, it is
    /// impossible to reliably implement this method on those operating systems.
    ///
    /// If you need your code to be cross-platform, please use `shared`/`shared_in` defined above.
    ///
    /// **Unstable**: This is platform specific and may go away in the future.
    #[cfg(any(windows, target_os = "linux"))]
    #[inline(always)]
    pub fn reopen(&self) -> io::Result<TempFile> {
        imp::reopen(&self.0).map(|f|TempFile(f))
    }
}

impl Read for TempFile {
    #[inline(always)]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for TempFile {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl Seek for TempFile {
    #[inline(always)]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.0.seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for TempFile {
    #[inline(always)]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        self.0.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for TempFile {
    #[inline(always)]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        self.0.as_raw_handle()
    }
}

/// A named temporary file.
///
/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
///
/// NamedTempFiles are deleted on drop. As rust doesn't guarantee that a struct will ever be
/// dropped, these temporary files will not be deleted on abort, resource leak, early exit, etc.
///
/// Please use TempFile unless you absolutely need a named file.
///
pub struct NamedTempFile(Option<NamedTempFileInner>);

struct NamedTempFileInner {
    file: File,
    path: PathBuf,
}

impl fmt::Debug for NamedTempFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
    }
}

#[derive(Debug)]
pub struct PersistError {
    pub error: io::Error,
    pub file: NamedTempFile,
}

impl From<PersistError> for io::Error {
    fn from(error: PersistError) -> io::Error {
        error.error
    }
}

impl fmt::Display for PersistError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "failed to persist temporary file: {}", self.error)
    }
}

impl error::Error for PersistError {
    fn description(&self) -> &str {
        "failed to persist temporary file"
    }
    fn cause(&self) -> Option<&error::Error> {
        Some(&self.error)
    }
}

impl NamedTempFile {
    /// Create a new temporary file.
    #[inline(always)]
    pub fn new() -> io::Result<NamedTempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    #[inline(always)]
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
        loop {
            let path = dir.as_ref().join(&util::tmpname());
            return match imp::create_named(&path) {
                Ok(file) => Ok(NamedTempFile(Some(NamedTempFileInner { path: path, file: file, }))),
                Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
                Err(e) => Err(e),
            }
        }
    }

    /// Number of bytes in the file.
    #[inline(always)]
    pub fn len(&self) -> io::Result<u64> {
        self.0.as_ref().unwrap().file.metadata().map(|m| m.len())
    }

    /// Truncate the file to `size` bytes.
    #[inline(always)]
    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.0.as_ref().unwrap().file.set_len(size)
    }

    /// Get the temporary file's path.
    #[inline(always)]
    pub fn path(&self) -> &Path {
        &self.0.as_ref().unwrap().path
    }

    /// Close and remove the temporary file.
    ///
    /// Use this if you want to detect errors in deleting the file.
    #[inline(always)]
    pub fn close(mut self) -> io::Result<()> {
        let NamedTempFileInner { path, file } = self.0.take().unwrap();
        drop(file);
        fs::remove_file(path)
    }

    /// Extract the path to the temporary file. Calling this will prevent the temporary file from
    /// being automatically deleted.
    #[inline(always)]
    pub fn into_path(mut self) -> PathBuf {
        let NamedTempFileInner { path, .. } = self.0.take().unwrap();
        path
    }

    /// Persist the temporary file at the target path.
    ///
    /// If a file exists at the target path, persist will atomically replace it. If this method
    /// fails, it will return `self` in the resulting PersistError.
    pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
        match fs::rename(&self.0.as_ref().unwrap().path, new_path) {
            Ok(_) => Ok(self.0.take().unwrap().file),
            Err(e) => Err(PersistError { file: self, error: e }),
        }
    }
}

impl Drop for NamedTempFile {
    #[inline(always)]
    fn drop(&mut self) {
        if let Some(NamedTempFileInner { file, path }) = self.0.take() {
            drop(file);
            let _ = fs::remove_file(path);
        }
    }
}

impl Read for NamedTempFile {
    #[inline(always)]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.as_mut().unwrap().file.read(buf)
    }
}

impl Write for NamedTempFile {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.as_mut().unwrap().file.write(buf)
    }
    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.0.as_mut().unwrap().file.flush()
    }
}

impl Seek for NamedTempFile {
    #[inline(always)]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.0.as_mut().unwrap().file.seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
    #[inline(always)]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        self.0.as_ref().unwrap().file.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
    #[inline(always)]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        self.0.as_ref().unwrap().file.as_raw_handle()
    }
}
<commit_msg>Fix inlining<commit_after>#![feature(convert, from_raw_os, collections)]
#![cfg_attr(windows, feature(fs_ext))]
//! Securely create and manage temporary files. Temporary files created by this create are
//! automatically deleted.
extern crate libc;
extern crate rand;

use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error;
use std::fmt;
use std::env;

mod imp;
mod util;

/// An unnamed temporary file.
///
/// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
///
/// Deletion:
///
/// Linux >= 3.11: The temporary file is never linked into the filesystem so it can't be leaked.
///
/// Other *nix: The temporary file is immediately unlinked on create. The OS will delete it when
/// the last open copy of it is closed (the last TempFile reference to it is dropped).
///
/// Windows: The temporary file is marked DeleteOnClose and, again, will be deleted when the last
/// open copy of it is closed. Unlike *nix operating systems, the file is not immediately unlinked
/// from the filesystem.
pub struct TempFile(File);

impl TempFile {
    /// Create a new temporary file.
    #[inline]
    pub fn new() -> io::Result<TempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    #[inline]
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<TempFile> {
        imp::create(dir.as_ref()).map(|f| TempFile(f))
    }

    /// Create a new temporary file and open it `count` times returning `count` independent
    /// references to the same file.
    ///
    /// This can be useful if you want multiple seek positions in the same temporary file.
    /// Additionally, this function guarantees that all of the returned temporary file objects
    /// refer to the same underlying temporary file even in the presence of a pathological
    /// temporary file cleaner.
    #[inline]
    pub fn shared(count: usize) -> io::Result<Vec<TempFile>> {
        Self::shared_in(&env::temp_dir(), count)
    }

    /// Same as `shared` but creates the file in the specified directory.
    #[inline]
    pub fn shared_in<P: AsRef<Path>>(dir: P, count: usize) -> io::Result<Vec<TempFile>> {
        imp::create_shared(dir.as_ref(), count).map(|files| files.map_in_place(|f|TempFile(f)))
    }

    /// Number of bytes in the file.
    #[inline]
    pub fn len(&self) -> io::Result<u64> {
        self.0.metadata().map(|m| m.len())
    }

    /// Truncate the file to `size` bytes.
    #[inline(always)]
    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.0.set_len(size)
    }

    /// Re-open the temporary file. The returned TempFile will refer to the same underlying
    /// temporary file but will have an independent offset.
    ///
    /// This method is only available on windows and Linux, not FreeBSD/MacOS. Unfortunately, it is
    /// impossible to reliably implement this method on those operating systems.
    ///
    /// If you need your code to be cross-platform, please use `shared`/`shared_in` defined above.
    ///
    /// **Unstable**: This is platform specific and may go away in the future.
    #[cfg(any(windows, target_os = "linux"))]
    #[inline]
    pub fn reopen(&self) -> io::Result<TempFile> {
        imp::reopen(&self.0).map(|f|TempFile(f))
    }
}

impl Read for TempFile {
    #[inline(always)]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for TempFile {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl Seek for TempFile {
    #[inline(always)]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.0.seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for TempFile {
    #[inline(always)]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        self.0.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for TempFile {
    #[inline(always)]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        self.0.as_raw_handle()
    }
}

/// A named temporary file.
///
/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
///
/// NamedTempFiles are deleted on drop. As rust doesn't guarantee that a struct will ever be
/// dropped, these temporary files will not be deleted on abort, resource leak, early exit, etc.
///
/// Please use TempFile unless you absolutely need a named file.
///
pub struct NamedTempFile(Option<NamedTempFileInner>);

struct NamedTempFileInner {
    file: File,
    path: PathBuf,
}

impl fmt::Debug for NamedTempFile {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
    }
}

#[derive(Debug)]
pub struct PersistError {
    pub error: io::Error,
    pub file: NamedTempFile,
}

impl From<PersistError> for io::Error {
    #[inline]
    fn from(error: PersistError) -> io::Error {
        error.error
    }
}

impl fmt::Display for PersistError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "failed to persist temporary file: {}", self.error)
    }
}

impl error::Error for PersistError {
    #[inline]
    fn description(&self) -> &str {
        "failed to persist temporary file"
    }
    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        Some(&self.error)
    }
}

impl NamedTempFile {
    /// Create a new temporary file.
    #[inline]
    pub fn new() -> io::Result<NamedTempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    #[inline]
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
        loop {
            let path = dir.as_ref().join(&util::tmpname());
            return match imp::create_named(&path) {
                Ok(file) => Ok(NamedTempFile(Some(NamedTempFileInner { path: path, file: file, }))),
                Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
                Err(e) => Err(e),
            }
        }
    }

    /// Number of bytes in the file.
    #[inline]
    pub fn len(&self) -> io::Result<u64> {
        self.0.as_ref().unwrap().file.metadata().map(|m| m.len())
    }

    /// Truncate the file to `size` bytes.
    #[inline]
    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.0.as_ref().unwrap().file.set_len(size)
    }

    /// Get the temporary file's path.
    #[inline]
    pub fn path(&self) -> &Path {
        &self.0.as_ref().unwrap().path
    }

    /// Close and remove the temporary file.
    ///
    /// Use this if you want to detect errors in deleting the file.
    #[inline]
    pub fn close(mut self) -> io::Result<()> {
        let NamedTempFileInner { path, file } = self.0.take().unwrap();
        drop(file);
        fs::remove_file(path)
    }

    /// Extract the path to the temporary file. Calling this will prevent the temporary file from
    /// being automatically deleted.
    #[inline]
    pub fn into_path(mut self) -> PathBuf {
        let NamedTempFileInner { path, .. } = self.0.take().unwrap();
        path
    }

    /// Persist the temporary file at the target path.
    ///
    /// If a file exists at the target path, persist will atomically replace it. If this method
    /// fails, it will return `self` in the resulting PersistError.
    #[inline]
    pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
        match fs::rename(&self.0.as_ref().unwrap().path, new_path) {
            Ok(_) => Ok(self.0.take().unwrap().file),
            Err(e) => Err(PersistError { file: self, error: e }),
        }
    }
}

impl Drop for NamedTempFile {
    #[inline]
    fn drop(&mut self) {
        if let Some(NamedTempFileInner { file, path }) = self.0.take() {
            drop(file);
            let _ = fs::remove_file(path);
        }
    }
}

impl Read for NamedTempFile {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.as_mut().unwrap().file.read(buf)
    }
}

impl Write for NamedTempFile {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.as_mut().unwrap().file.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.as_mut().unwrap().file.flush()
    }
}

impl Seek for NamedTempFile {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.0.as_mut().unwrap().file.seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
    #[inline]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        self.0.as_ref().unwrap().file.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
    #[inline]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        self.0.as_ref().unwrap().file.as_raw_handle()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The syscall.rs Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

//! Raw system calls for Rust.

#![crate_name="syscall"]
#![crate_type="lib"]

#![feature(macro_rules, asm, globs)]
#![no_std]

#[cfg(test)]
extern crate std;

#[cfg(test)]
extern crate native;

pub use platform::*;

pub mod macros;

#[cfg(target_os="linux", target_arch="x86_64")]
#[path="platform/linux-x86_64/mod.rs"]
pub mod platform;
<commit_msg>Link libcore<commit_after>// Copyright 2014 The syscall.rs Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

//! Raw system calls for Rust.

#![crate_name="syscall"]
#![crate_type="lib"]

#![feature(macro_rules, asm, globs)]
#![no_std]

extern crate core;

#[cfg(test)]
extern crate std;

#[cfg(test)]
extern crate native;

pub use platform::*;

pub mod macros;

#[cfg(target_os="linux", target_arch="x86_64")]
#[path="platform/linux-x86_64/mod.rs"]
pub mod platform;
<|endoftext|>


<commit_before>//! # Console progress bar for Rust
//!
//! Console progress bar for Rust Inspired from [pb](http://github.com/cheggaaa/pb).
//! support and tested on MacOS and Linux(should work on Windows too, but not tested yet).
//!
//! ![Screenshot](https://raw.githubusercontent.com/a8m/pb/master/gif/rec.gif)
//!
//! ### Examples
//! 1. simple example
//!
//! ```no_run
//! extern crate pbr;
//!
//! use pbr::ProgressBar;
//! use std::thread;
//!
//! fn main() {
//!     let count = 1000;
//!     let mut pb = ProgressBar::new(count);
//!     for _ in 0..count {
//!         pb.inc();
//!         thread::sleep_ms(200);
//!     }
//!     println!("done!");
//! }
//! ```
//!
//! 2. Broadcast writing(simple file copying)
//!
//! ```no_run
//! #![feature(io)]
//! extern crate pbr;
//!
//! use std::io::copy;
//! use std::io::prelude::*;
//! use std::fs::{self, File};
//! use pbr::{ProgressBar, Units};
//!
//! fn main() {
//!     let fname = "/usr/share/dict/words";
//!     let mut file = File::open(fname).unwrap();
//!     let n_bytes = fs::metadata(fname).unwrap().len() as usize;
//!     let mut pb = ProgressBar::new(n_bytes);
//!     pb.set_units(Units::Bytes);
//!     let mut dfile = File::create("copy-words").unwrap();
//!     let mut handle = dfile.broadcast(&mut pb);
//!     copy(&mut file, &mut handle).unwrap();
//!     println!("done!");
//! }
//! ```
extern crate time;
mod tty;
mod pb;
pub use pb::{ProgressBar, Units};
<commit_msg>docs(lib): refac example in lib<commit_after>//! # Console progress bar for Rust
//!
//! Console progress bar for Rust Inspired from [pb](http://github.com/cheggaaa/pb).
//! support and tested on MacOS and Linux(should work on Windows too, but not tested yet).
//!
//! ![Screenshot](https://raw.githubusercontent.com/a8m/pb/master/gif/rec.gif)
//!
//! ### Examples
//! 1. simple example
//!
//! ```no_run
//! extern crate pbr;
//!
//! use pbr::ProgressBar;
//! use std::thread;
//!
//! fn main() {
//!     let count = 1000;
//!     let mut pb = ProgressBar::new(count);
//!     for _ in 0..count {
//!         pb.inc();
//!         thread::sleep_ms(200);
//!     }
//!     println!("done!");
//! }
//! ```
//!
//! 2. Broadcast writing(simple file copying)
//!
//! ```no_run
//! #![feature(io)]
//! extern crate pbr;
//!
//! use std::io::copy;
//! use std::io::prelude::*;
//! use std::fs::File;
//! use pbr::{ProgressBar, Units};
//!
//! fn main() {
//!     let mut file = File::open("/usr/share/dict/words").unwrap();
//!     let n_bytes = file.metadata().unwrap().len() as usize;
//!     let mut pb = ProgressBar::new(n_bytes);
//!     pb.set_units(Units::Bytes);
//!     let mut handle = File::create("copy-words").unwrap().broadcast(&mut pb);
//!     copy(&mut file, &mut handle).unwrap();
//!     println!("done!");
//! }
//! ```
extern crate time;
mod tty;
mod pb;
pub use pb::{ProgressBar, Units};
<|endoftext|>


<commit_before>
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;

trait AtomicCounter {
    type PrimitiveType;

    fn inc(&self);
    fn add(&self, amount: Self::PrimitiveType);
    fn reset(&self) -> Self::PrimitiveType;
}

impl AtomicCounter for AtomicUsize {
    type PrimitiveType = usize;

    fn inc(&self) {
        self.add(1)
    }

    fn add(&self, amount: usize) {
        self.fetch_add(amount, Relaxed);
    }

    fn reset(&self) -> usize {
        let mut last_value = 0;
        loop {
            let ret = self.compare_and_swap(last_value, 0, Relaxed);
            if ret == last_value {
                break;
            }
            last_value = ret;
        }
        last_value
    }
}

#[cfg(test)]
mod tests {

    use std::thread;
    use std::sync::Arc;
    use std::ops::Deref;

    use super::*;

    const NUM_THREADS: usize = 29;
    const NUM_ITERATIONS: usize = 7_000_000;

    #[test]
    fn test_inc() {
        let mut join_handles = Vec::new();
        let counter = Arc::new(AtomicUsize::new(0));
        println!("test_inc: Spawning {} threads, each with {} iterations...", NUM_THREADS, NUM_ITERATIONS);
        for _ in 0..NUM_THREADS {
            let counter_ref = counter.clone();
            join_handles.push(thread::spawn(move || {
                //make sure we're not going though Arc on each iteration
                let counter: &AtomicUsize = counter_ref.deref();
                for _ in 0..NUM_ITERATIONS {
                    counter.inc();
                }
            }));
        }
        for handle in join_handles {
            handle.join().unwrap();
        }
        let count = counter.reset();
        println!("test_inc: Got count: {}", count);
        assert_eq!(NUM_THREADS * NUM_ITERATIONS, count);
    }

    #[test]
    fn test_add() {
        let mut join_handles = Vec::new();
        let counter = Arc::new(AtomicUsize::new(0));
        println!("test_add: Spawning {} threads, each with {} iterations...", NUM_THREADS, NUM_ITERATIONS);
        let mut expected_count = 0;
        for to_add in 0..NUM_THREADS {
            let counter_ref = counter.clone();
            expected_count += to_add * NUM_ITERATIONS;
            join_handles.push(thread::spawn(move || {
                //make sure we're not going though Arc on each iteration
                let counter: &AtomicUsize = counter_ref.deref();
                for _ in 0..NUM_ITERATIONS {
                    counter.add(to_add);
                }
            }));
        }
        for handle in join_handles {
            handle.join().unwrap();
        }
        let count = counter.reset();
        println!("test_add: Expected count: {}, got count: {}", expected_count, count);
        assert_eq!(expected_count, count);
    }

    #[test]
    fn test_add_reset() {
        let mut join_handles = Vec::new();
        let counter = Arc::new(AtomicUsize::new(0));
        println!("test_add_reset: Spawning {} threads, each with {} iterations...", NUM_THREADS, NUM_ITERATIONS);
        let mut expected_count = 0;
        for to_add in 0..NUM_THREADS {
            expected_count += to_add * NUM_ITERATIONS;
        }

        // setup thread that `reset()`s all the time
        let counter_ref = counter.clone();
        let reset_handle = thread::spawn(move || {
            // Usually, you would check for some better termination condition.
            // I don't want to pollute my test with thread synchronization
            // operations outside of AtomicCounter, hence this approach.
            let mut total_count = 0;
            let counter: &AtomicUsize = counter_ref.deref();
            while total_count < expected_count {
                total_count += counter.reset();
            }
            // Ok, now we got the total_count but this could just be lucky.
            // Better do some more resets to be sure... ;)
            for _ in 0..NUM_ITERATIONS {
                total_count += counter.reset();
            }
            total_count
        });

        for to_add in 0..NUM_THREADS {
            let counter_ref = counter.clone();

            join_handles.push(thread::spawn(move || {
                //make sure we're not going though Arc on each iteration
                let counter: &AtomicUsize = counter_ref.deref();
                for _ in 0..NUM_ITERATIONS {
                    counter.add(to_add);
                }
            }));
        }
        for handle in join_handles {
            handle.join().unwrap();
        }
        let actual_count = reset_handle.join().unwrap();
        println!("test_add_reset: Expected count: {}, got count: {}", expected_count, actual_count);
        assert_eq!(expected_count, actual_count);
    }

}
<commit_msg>Find out AtomicUsize.swap() exists<commit_after>
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;

trait AtomicCounter {
    type PrimitiveType;

    fn inc(&self);
    fn add(&self, amount: Self::PrimitiveType);
    fn reset(&self) -> Self::PrimitiveType;
}

impl AtomicCounter for AtomicUsize {
    type PrimitiveType = usize;

    fn inc(&self) {
        self.add(1)
    }

    fn add(&self, amount: usize) {
        self.fetch_add(amount, Relaxed);
    }

    fn reset(&self) -> usize {
        self.swap(0, Relaxed)
    }
}

#[cfg(test)]
mod tests {

    use std::thread;
    use std::sync::Arc;
    use std::ops::Deref;

    use super::*;

    const NUM_THREADS: usize = 29;
    const NUM_ITERATIONS: usize = 7_000_000;

    #[test]
    fn test_inc() {
        let mut join_handles = Vec::new();
        let counter = Arc::new(AtomicUsize::new(0));
        println!("test_inc: Spawning {} threads, each with {} iterations...", NUM_THREADS, NUM_ITERATIONS);
        for _ in 0..NUM_THREADS {
            let counter_ref = counter.clone();
            join_handles.push(thread::spawn(move || {
                //make sure we're not going though Arc on each iteration
                let counter: &AtomicUsize = counter_ref.deref();
                for _ in 0..NUM_ITERATIONS {
                    counter.inc();
                }
            }));
        }
        for handle in join_handles {
            handle.join().unwrap();
        }
        let count = counter.reset();
        println!("test_inc: Got count: {}", count);
        assert_eq!(NUM_THREADS * NUM_ITERATIONS, count);
    }

    #[test]
    fn test_add() {
        let mut join_handles = Vec::new();
        let counter = Arc::new(AtomicUsize::new(0));
        println!("test_add: Spawning {} threads, each with {} iterations...", NUM_THREADS, NUM_ITERATIONS);
        let mut expected_count = 0;
        for to_add in 0..NUM_THREADS {
            let counter_ref = counter.clone();
            expected_count += to_add * NUM_ITERATIONS;
            join_handles.push(thread::spawn(move || {
                //make sure we're not going though Arc on each iteration
                let counter: &AtomicUsize = counter_ref.deref();
                for _ in 0..NUM_ITERATIONS {
                    counter.add(to_add);
                }
            }));
        }
        for handle in join_handles {
            handle.join().unwrap();
        }
        let count = counter.reset();
        println!("test_add: Expected count: {}, got count: {}", expected_count, count);
        assert_eq!(expected_count, count);
    }

    #[test]
    fn test_add_reset() {
        let mut join_handles = Vec::new();
        let counter = Arc::new(AtomicUsize::new(0));
        println!("test_add_reset: Spawning {} threads, each with {} iterations...", NUM_THREADS, NUM_ITERATIONS);
        let mut expected_count = 0;
        for to_add in 0..NUM_THREADS {
            expected_count += to_add * NUM_ITERATIONS;
        }

        // setup thread that `reset()`s all the time
        let counter_ref = counter.clone();
        let reset_handle = thread::spawn(move || {
            // Usually, you would check for some better termination condition.
            // I don't want to pollute my test with thread synchronization
            // operations outside of AtomicCounter, hence this approach.
            let mut total_count = 0;
            let counter: &AtomicUsize = counter_ref.deref();
            while total_count < expected_count {
                total_count += counter.reset();
            }
            // Ok, now we got the total_count but this could just be lucky.
            // Better do some more resets to be sure... ;)
            for _ in 0..NUM_ITERATIONS {
                total_count += counter.reset();
            }
            total_count
        });

        for to_add in 0..NUM_THREADS {
            let counter_ref = counter.clone();

            join_handles.push(thread::spawn(move || {
                //make sure we're not going though Arc on each iteration
                let counter: &AtomicUsize = counter_ref.deref();
                for _ in 0..NUM_ITERATIONS {
                    counter.add(to_add);
                }
            }));
        }
        for handle in join_handles {
            handle.join().unwrap();
        }
        let actual_count = reset_handle.join().unwrap();
        println!("test_add_reset: Expected count: {}, got count: {}", expected_count, actual_count);
        assert_eq!(expected_count, actual_count);
    }

}
<|endoftext|>