<commit_before>// Copyright Ethereum Classic Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Big unsigned integer types
//!
//! Implementation of a various large-but-fixed sized unsigned integer types.
//! The functions here are designed to be fast.
//!

// #![no_std]

use ::std::convert::{From, Into};
use ::std::ops::{Add, Sub, Not, Mul, Div, Shr, Shl};
use ::std::cmp::Ordering;

#[repr(C)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct U256([u64; 4]);

impl U256 {
    pub fn zero() -> U256 { U256([0; 4]) }
    pub fn one() -> U256 { U256([1u64, 0u64, 0u64, 0u64]) }

    pub fn overflowing_add(self, other: U256) -> (U256, bool) {
        let U256(ref me) = self;
        let U256(ref you) = other;

        let mut ret = [0u64; 4];
        let mut carry = false;
        for i in 0..4 {
            let (v, o1) = me[i].overflowing_add(you[i]);
            let (v, o2) = v.overflowing_add(if carry { 1 } else { 0 });
            ret[i] = v;
            carry = o1 || o2;
        }

        (U256(ret), carry)
    }

    pub fn low_u32(&self) -> u32 {
        let &U256(ref arr) = self;
        arr[0] as u32
    }

    pub fn mul_u32(self, other: u32) -> U256 {
        let U256(ref arr) = self;
        let mut carry = [0u64; 4];
        let mut ret = [0u64; 4];
        for i in 0..4 {
            let upper = other as u64 * (arr[i] >> 32);
            let lower = other as u64 * (arr[i] & 0xFFFFFFFF);
            if i < 3 {
                carry[i + 1] += upper >> 32;
            }
            ret[i] = lower + (upper << 32);
        }
        U256(ret) + U256(carry)
    }

    pub fn bits(&self) -> usize {
        let &U256(ref arr) = self;
        for i in 1..4 {
            if arr[4 - i] > 0 { return (0x40 * (4 - i + 1)) - arr[4 - i].leading_zeros() as usize; }
        }
        0x40 - arr[0].leading_zeros() as usize
    }

    pub fn log2floor(&self) -> isize {
        assert!(*self != U256::zero());
        let mut l: isize = 256;
        for i in 0..4 {
            if self.0[3 - i] == 0u64 {
                l -= 64;
            } else {
                l -= self.0[3 - i].leading_zeros() as isize;
                return l;
            }
        }
        return l;
    }
}

impl From<u64> for U256 {
    fn from(val: u64) -> U256 {
        U256([0, 0, 0, val])
    }
}

impl Into<u64> for U256 {
    fn into(self) -> u64 {
        assert!(self.0[0] == 0 && self.0[1] == 0 && self.0[2] == 0);
        self.0[3]
    }
}

impl From<usize> for U256 {
    fn from(val: usize) -> U256 {
        (val as u64).into()
    }
}

impl Into<usize> for U256 {
    fn into(self) -> usize {
        let v64: u64 = self.into();
        v64 as usize
    }
}

impl From<i32> for U256 {
    fn from(val: i32) -> U256 {
        (val as u64).into()
    }
}

impl<'a> From<&'a [u8]> for U256 {
    fn from(val: &'a [u8]) -> U256 {
        assert!(val.len() <= 256 / 8);
        let mut u256 = U256::zero();

        for i in 0..val.len() {
            let rev = val.len() - 1 - i;
            let pos = rev / 8;
            u256.0[pos] += (val[i] as u64) << ((rev % 8) * 8);
        }

        u256
    }
}

impl Not for U256 {
    type Output = U256;

    fn not(self) -> U256 {
        let U256(ref arr) = self;
        let mut ret = [0u64; 4];
        for i in 0..4 {
            ret[i] = !arr[i];
        }
        U256(ret)
    }
}

impl Add for U256 {
    type Output = U256;

    fn add(self, other: U256) -> U256 {
        let (o, v) = self.overflowing_add(other);
        assert!(v == false);
        o
    }
}

impl Sub for U256 {
    type Output = U256;

    #[inline]
    fn sub(self, other: U256) -> U256 {
        let (o, v) = self.overflowing_add(!other);
        assert!(v == true);
        o + U256::one()
    }
}

impl Mul for U256 {
    type Output = U256;

    fn mul(self, other: U256) -> U256 {
        let mut me = self;
        // TODO: be more efficient about this
        for i in 0..(2 * 4) {
            me = (me + me.mul_u32((other >> (32 * i)).low_u32())) << (32 * i);
        }
        me
    }
}

impl Div for U256 {
    type Output = U256;

    fn div(self, other: U256) -> U256 {
        let mut sub_copy = self;
        let mut shift_copy = other;
        let mut ret = [0u64; 4];

        let my_bits = self.bits();
        let your_bits = other.bits();

        // Check for division by 0
        assert!(your_bits != 0);

        // Early return in case we are dividing by a larger number than us
        if my_bits < your_bits {
            return U256(ret);
        }

        // Bitwise long division
        let mut shift = my_bits - your_bits;
        shift_copy = shift_copy << shift;
        loop {
            if sub_copy >= shift_copy {
                ret[shift / 64] |= 1 << (shift % 64);
                sub_copy = sub_copy - shift_copy;
            }
            shift_copy = shift_copy >> 1;
            if shift == 0 { break; }
            shift -= 1;
        }

        U256(ret)
    }
}

impl Ord for U256 {
    fn cmp(&self, other: &U256) -> Ordering {
	let &U256(ref me) = self;
	let &U256(ref you) = other;
	let mut i = 4;
	while i > 0 {
	    i -= 1;
	    if me[i] < you[i] { return Ordering::Less; }
	    if me[i] > you[i] { return Ordering::Greater; }
	}
	Ordering::Equal
    }
}

impl PartialOrd for U256 {
    fn partial_cmp(&self, other: &U256) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Shl<usize> for U256 {
    type Output = U256;

    fn shl(self, shift: usize) -> U256 {
        let U256(ref original) = self;
        let mut ret = [0u64; 4];
        let word_shift = shift / 64;
        let bit_shift = shift % 64;
        for i in 0..4 {
            // Shift
            if bit_shift < 64 && i + word_shift < 4 {
                ret[i + word_shift] += original[i] << bit_shift;
            }
            // Carry
            if bit_shift > 0 && i + word_shift + 1 < 4 {
                ret[i + word_shift + 1] += original[i] >> (64 - bit_shift);
            }
        }
        U256(ret)
    }
}

impl Shr<usize> for U256 {
    type Output = U256;

    fn shr(self, shift: usize) -> U256 {
        let U256(ref original) = self;
        let mut ret = [0u64; 4];
        let word_shift = shift / 64;
        let bit_shift = shift % 64;
        for i in word_shift..4 {
            // Shift
            ret[i - word_shift] += original[i] >> bit_shift;
            // Carry
            if bit_shift > 0 && i < 4 - 1 {
                ret[i - word_shift] += original[i + 1] << (64 - bit_shift);
            }
        }
        U256(ret)
    }
}

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

    #[test]
    fn u256_add() {
        assert_eq!(
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64]) +
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64]),
            U256([0xfffffffffffffffeu64, 1u64, 0u64, 0u64])
        );
    }

    #[test]
    fn u256_sub() {
        assert_eq!(
            U256([0xfffffffffffffffeu64, 1u64, 0u64, 0u64]) -
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64]),
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64])
        );
    }

    #[test]
    fn u256_log2floor() {
        assert_eq!(
            U256([u64::max_value(), u64::max_value(), u64::max_value(), u64::max_value()])
                .log2floor(),
            256, "testing log2floor for max value");
        assert_eq!(
            U256([0x1u64, 0u64, 0u64, 0u64]).log2floor(),
            1, "testing log2floor for 1");
    }
}
<commit_msg>Problem: some U256 implementation is wrong Solution: fix From<u64>, Into<u64> and add several helper functions<commit_after>// Copyright Ethereum Classic Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Big unsigned integer types
//!
//! Implementation of a various large-but-fixed sized unsigned integer types.
//! The functions here are designed to be fast.
//!

// #![no_std]

use ::std::convert::{From, Into};
use ::std::ops::{Add, Sub, Not, Mul, Div, Shr, Shl};
use ::std::cmp::Ordering;

#[repr(C)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct U256([u64; 4]);

impl U256 {
    pub fn zero() -> U256 { 0.into() }
    pub fn one() -> U256 { 1.into() }

    pub fn max_value() -> U256 {
        !U256::zero()
    }

    pub fn min_value() -> U256 {
        U256::zero()
    }

    pub fn overflowing_add(self, other: U256) -> (U256, bool) {
        let U256(ref me) = self;
        let U256(ref you) = other;

        let mut ret = [0u64; 4];
        let mut carry = false;
        for i in 0..4 {
            let (v, o1) = me[i].overflowing_add(you[i]);
            let (v, o2) = v.overflowing_add(if carry { 1 } else { 0 });
            ret[i] = v;
            carry = o1 || o2;
        }

        (U256(ret), carry)
    }

    pub fn low_u32(&self) -> u32 {
        let &U256(ref arr) = self;
        arr[0] as u32
    }

    pub fn mul_u32(self, other: u32) -> U256 {
        let U256(ref arr) = self;
        let mut carry = [0u64; 4];
        let mut ret = [0u64; 4];
        for i in 0..4 {
            let upper = other as u64 * (arr[i] >> 32);
            let lower = other as u64 * (arr[i] & 0xFFFFFFFF);
            if i < 3 {
                carry[i + 1] += upper >> 32;
            }
            ret[i] = lower + (upper << 32);
        }
        U256(ret) + U256(carry)
    }

    pub fn bits(&self) -> usize {
        let &U256(ref arr) = self;
        for i in 1..4 {
            if arr[4 - i] > 0 { return (0x40 * (4 - i + 1)) - arr[4 - i].leading_zeros() as usize; }
        }
        0x40 - arr[0].leading_zeros() as usize
    }

    pub fn log2floor(&self) -> isize {
        assert!(*self != U256::zero());
        let mut l: isize = 256;
        for i in 0..4 {
            if self.0[3 - i] == 0u64 {
                l -= 64;
            } else {
                l -= self.0[3 - i].leading_zeros() as isize;
                return l;
            }
        }
        return l;
    }
}

impl From<u64> for U256 {
    fn from(val: u64) -> U256 {
        U256([val, 0, 0, 0])
    }
}

impl Into<u64> for U256 {
    fn into(self) -> u64 {
        assert!(self.0[1] == 0 && self.0[2] == 0 && self.0[3] == 0);
        self.0[0]
    }
}

impl From<usize> for U256 {
    fn from(val: usize) -> U256 {
        (val as u64).into()
    }
}

impl Into<usize> for U256 {
    fn into(self) -> usize {
        let v64: u64 = self.into();
        v64 as usize
    }
}

impl From<i32> for U256 {
    fn from(val: i32) -> U256 {
        (val as u64).into()
    }
}

impl<'a> From<&'a [u8]> for U256 {
    fn from(val: &'a [u8]) -> U256 {
        assert!(val.len() <= 256 / 8);
        let mut u256 = U256::zero();

        for i in 0..val.len() {
            let rev = val.len() - 1 - i;
            let pos = rev / 8;
            u256.0[pos] += (val[i] as u64) << ((rev % 8) * 8);
        }

        u256
    }
}

impl Not for U256 {
    type Output = U256;

    fn not(self) -> U256 {
        let U256(ref arr) = self;
        let mut ret = [0u64; 4];
        for i in 0..4 {
            ret[i] = !arr[i];
        }
        U256(ret)
    }
}

impl Add for U256 {
    type Output = U256;

    fn add(self, other: U256) -> U256 {
        let (o, v) = self.overflowing_add(other);
        assert!(v == false);
        o
    }
}

impl Sub for U256 {
    type Output = U256;

    #[inline]
    fn sub(self, other: U256) -> U256 {
        let (o, v) = self.overflowing_add(!other);
        assert!(v == true);
        o + U256::one()
    }
}

impl Mul for U256 {
    type Output = U256;

    fn mul(self, other: U256) -> U256 {
        let mut me = self;
        // TODO: be more efficient about this
        for i in 0..(2 * 4) {
            me = (me + me.mul_u32((other >> (32 * i)).low_u32())) << (32 * i);
        }
        me
    }
}

impl Div for U256 {
    type Output = U256;

    fn div(self, other: U256) -> U256 {
        let mut sub_copy = self;
        let mut shift_copy = other;
        let mut ret = [0u64; 4];

        let my_bits = self.bits();
        let your_bits = other.bits();

        // Check for division by 0
        assert!(your_bits != 0);

        // Early return in case we are dividing by a larger number than us
        if my_bits < your_bits {
            return U256(ret);
        }

        // Bitwise long division
        let mut shift = my_bits - your_bits;
        shift_copy = shift_copy << shift;
        loop {
            if sub_copy >= shift_copy {
                ret[shift / 64] |= 1 << (shift % 64);
                sub_copy = sub_copy - shift_copy;
            }
            shift_copy = shift_copy >> 1;
            if shift == 0 { break; }
            shift -= 1;
        }

        U256(ret)
    }
}

impl Ord for U256 {
    fn cmp(&self, other: &U256) -> Ordering {
	let &U256(ref me) = self;
	let &U256(ref you) = other;
	let mut i = 4;
	while i > 0 {
	    i -= 1;
	    if me[i] < you[i] { return Ordering::Less; }
	    if me[i] > you[i] { return Ordering::Greater; }
	}
	Ordering::Equal
    }
}

impl PartialOrd for U256 {
    fn partial_cmp(&self, other: &U256) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Shl<usize> for U256 {
    type Output = U256;

    fn shl(self, shift: usize) -> U256 {
        let U256(ref original) = self;
        let mut ret = [0u64; 4];
        let word_shift = shift / 64;
        let bit_shift = shift % 64;
        for i in 0..4 {
            // Shift
            if bit_shift < 64 && i + word_shift < 4 {
                ret[i + word_shift] += original[i] << bit_shift;
            }
            // Carry
            if bit_shift > 0 && i + word_shift + 1 < 4 {
                ret[i + word_shift + 1] += original[i] >> (64 - bit_shift);
            }
        }
        U256(ret)
    }
}

impl Shr<usize> for U256 {
    type Output = U256;

    fn shr(self, shift: usize) -> U256 {
        let U256(ref original) = self;
        let mut ret = [0u64; 4];
        let word_shift = shift / 64;
        let bit_shift = shift % 64;
        for i in word_shift..4 {
            // Shift
            ret[i - word_shift] += original[i] >> bit_shift;
            // Carry
            if bit_shift > 0 && i < 4 - 1 {
                ret[i - word_shift] += original[i + 1] << (64 - bit_shift);
            }
        }
        U256(ret)
    }
}

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

    #[test]
    fn u256_add() {
        assert_eq!(
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64]) +
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64]),
            U256([0xfffffffffffffffeu64, 1u64, 0u64, 0u64])
        );
    }

    #[test]
    fn u256_overflowing_add() {
        assert_eq!(
            U256::max_value().overflowing_add(U256::one() + U256::one()).0,
            U256::one()
        );
    }

    #[test]
    fn u256_sub() {
        assert_eq!(
            U256([0xfffffffffffffffeu64, 1u64, 0u64, 0u64]) -
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64]),
            U256([0xffffffffffffffffu64, 0u64, 0u64, 0u64])
        );
    }

    #[test]
    fn u256_not() {
        assert_eq!(
            !U256::min_value(),
            U256([0xffffffffffffffffu64, 0xffffffffffffffffu64,
                  0xffffffffffffffffu64, 0xffffffffffffffffu64])
        );
        assert_eq!(
            !U256::max_value(),
            U256([0u64, 0u64, 0u64, 0u64])
        );
    }

    #[test]
    fn u256_log2floor() {
        assert_eq!(
            U256([u64::max_value(), u64::max_value(), u64::max_value(), u64::max_value()])
                .log2floor(),
            256, "testing log2floor for max value");
        assert_eq!(
            U256([0x1u64, 0u64, 0u64, 0u64]).log2floor(),
            1, "testing log2floor for 1");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use parking_lot::RwLock;
use elements::{GlobalType, ValueType, TableElementType};
use interpreter::Error;
use interpreter::value::RuntimeValue;

/// Variable type.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VariableType {
	/// Any func value.
	AnyFunc,
	/// i32 value.
	I32,
	/// i64 value.
	I64,
	/// f32 value.
	F32,
	/// f64 value.
	F64,
}

/// Externally stored variable value.
pub trait ExternalVariableValue {
	/// Get variable value.
	fn get(&self) -> RuntimeValue;

	/// Set variable value.
	///
	/// WebAssembly specificaiton [requires][0] that if global variable is immutable, then
	/// it should remain unchanged.
	///
	/// [0]: https://webassembly.github.io/spec/appendix/properties.html#global-instance
	fn set(&mut self, value: RuntimeValue) -> Result<(), Error>;
}

/// Variable instance.
#[derive(Debug)]
pub struct VariableInstance {
	/// Is mutable?
	is_mutable: bool,
	/// Variable type.
	variable_type: VariableType,
	/// Global value.
	value: RwLock<VariableValue>,
}

/// Enum variable value.
enum VariableValue {
	/// Internal value.
	Internal(RuntimeValue),
	/// External value.
	External(Box<ExternalVariableValue>),
}

impl VariableInstance {
	/// New variable instance
	pub fn new(is_mutable: bool, variable_type: VariableType, value: RuntimeValue) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		if !value.is_null() && value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::Internal(value)),
		})
	}

	/// New global variable
	pub fn new_global(global_type: &GlobalType, value: RuntimeValue) -> Result<Self, Error> {
		Self::new(global_type.is_mutable(), global_type.content_type().into(), value)
	}

	/// New global with externally stored value.
	pub fn new_external_global(is_mutable: bool, variable_type: VariableType, value: Box<ExternalVariableValue>) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		let current_value = value.get();
		if !current_value.is_null() && current_value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, current_value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::External(value)),
		})
	}

	/// Is mutable
	pub fn is_mutable(&self) -> bool {
		self.is_mutable
	}

	/// Get variable type.
	pub fn variable_type(&self) -> VariableType {
		self.variable_type
	}

	/// Get the value of the variable instance
	pub fn get(&self) -> RuntimeValue {
		self.value.read().get()
	}

	/// Set the value of the variable instance
	pub fn set(&self, value: RuntimeValue) -> Result<(), Error> {
		if !self.is_mutable {
			return Err(Error::Variable("trying to update immutable variable".into()));
		}
		if value.variable_type() != Some(self.variable_type) {
			return Err(Error::Variable(format!("trying to update variable of type {:?} with value of type {:?}", self.variable_type, value.variable_type())));
		}

		self.value.write().set(value)
	}
}

impl VariableValue {
	fn get(&self) -> RuntimeValue {
		match *self {
			VariableValue::Internal(ref value) => value.clone(),
			VariableValue::External(ref value) => value.get(),
		}
	}

	fn set(&mut self, new_value: RuntimeValue) -> Result<(), Error> {
		match *self {
			VariableValue::Internal(ref mut value) => {
				*value = new_value;
				Ok(())
			},
			VariableValue::External(ref mut value) => value.set(new_value),
		}
	}
}

impl From<ValueType> for VariableType {
	fn from(vt: ValueType) -> VariableType {
		match vt {
			ValueType::I32 => VariableType::I32,
			ValueType::I64 => VariableType::I64,
			ValueType::F32 => VariableType::F32,
			ValueType::F64 => VariableType::F64,
		}
	}
}

impl From<TableElementType> for VariableType {
	fn from(tt: TableElementType) -> VariableType {
		match tt {
			TableElementType::AnyFunc => VariableType::AnyFunc,
		}
	}
}

impl fmt::Debug for VariableValue {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			VariableValue::Internal(ref value) => write!(f, "Variable.Internal({:?})", value),
			VariableValue::External(ref value) => write!(f, "Variable.External({:?})", value.get()),
		}
	}
}
<commit_msg>Move comment about spec to the trait header.<commit_after>use std::fmt;
use parking_lot::RwLock;
use elements::{GlobalType, ValueType, TableElementType};
use interpreter::Error;
use interpreter::value::RuntimeValue;

/// Variable type.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VariableType {
	/// Any func value.
	AnyFunc,
	/// i32 value.
	I32,
	/// i64 value.
	I64,
	/// f32 value.
	F32,
	/// f64 value.
	F64,
}

/// Externally stored variable value.
///
/// WebAssembly specificaiton [requires][0] that if a global variable is immutable, then
/// it should remain unchanged. To comply with specification you should ensure this invariant holds.
///
/// [0]: https://webassembly.github.io/spec/appendix/properties.html#global-instance
pub trait ExternalVariableValue {
	/// Get variable value.
	fn get(&self) -> RuntimeValue;

	/// Set variable value.
	fn set(&mut self, value: RuntimeValue) -> Result<(), Error>;
}

/// Variable instance.
#[derive(Debug)]
pub struct VariableInstance {
	/// Is mutable?
	is_mutable: bool,
	/// Variable type.
	variable_type: VariableType,
	/// Global value.
	value: RwLock<VariableValue>,
}

/// Enum variable value.
enum VariableValue {
	/// Internal value.
	Internal(RuntimeValue),
	/// External value.
	External(Box<ExternalVariableValue>),
}

impl VariableInstance {
	/// New variable instance
	pub fn new(is_mutable: bool, variable_type: VariableType, value: RuntimeValue) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		if !value.is_null() && value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::Internal(value)),
		})
	}

	/// New global variable
	pub fn new_global(global_type: &GlobalType, value: RuntimeValue) -> Result<Self, Error> {
		Self::new(global_type.is_mutable(), global_type.content_type().into(), value)
	}

	/// New global with externally stored value.
	pub fn new_external_global(is_mutable: bool, variable_type: VariableType, value: Box<ExternalVariableValue>) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		let current_value = value.get();
		if !current_value.is_null() && current_value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, current_value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::External(value)),
		})
	}

	/// Is mutable
	pub fn is_mutable(&self) -> bool {
		self.is_mutable
	}

	/// Get variable type.
	pub fn variable_type(&self) -> VariableType {
		self.variable_type
	}

	/// Get the value of the variable instance
	pub fn get(&self) -> RuntimeValue {
		self.value.read().get()
	}

	/// Set the value of the variable instance
	pub fn set(&self, value: RuntimeValue) -> Result<(), Error> {
		if !self.is_mutable {
			return Err(Error::Variable("trying to update immutable variable".into()));
		}
		if value.variable_type() != Some(self.variable_type) {
			return Err(Error::Variable(format!("trying to update variable of type {:?} with value of type {:?}", self.variable_type, value.variable_type())));
		}

		self.value.write().set(value)
	}
}

impl VariableValue {
	fn get(&self) -> RuntimeValue {
		match *self {
			VariableValue::Internal(ref value) => value.clone(),
			VariableValue::External(ref value) => value.get(),
		}
	}

	fn set(&mut self, new_value: RuntimeValue) -> Result<(), Error> {
		match *self {
			VariableValue::Internal(ref mut value) => {
				*value = new_value;
				Ok(())
			},
			VariableValue::External(ref mut value) => value.set(new_value),
		}
	}
}

impl From<ValueType> for VariableType {
	fn from(vt: ValueType) -> VariableType {
		match vt {
			ValueType::I32 => VariableType::I32,
			ValueType::I64 => VariableType::I64,
			ValueType::F32 => VariableType::F32,
			ValueType::F64 => VariableType::F64,
		}
	}
}

impl From<TableElementType> for VariableType {
	fn from(tt: TableElementType) -> VariableType {
		match tt {
			TableElementType::AnyFunc => VariableType::AnyFunc,
		}
	}
}

impl fmt::Debug for VariableValue {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			VariableValue::Internal(ref value) => write!(f, "Variable.Internal({:?})", value),
			VariableValue::External(ref value) => write!(f, "Variable.External({:?})", value.get()),
		}
	}
}
<|endoftext|>


<commit_before>#![feature(zero_one)]

extern crate deeplearn;
extern crate matrix;

use std::fs::File;
use std::io::{
    self,
    BufReader,
    Read,
};
use std::num::{Zero, One};
use std::path::Path;

use deeplearn::Graph;
use deeplearn::op::{Add, MatMul, Mse, Relu};
use deeplearn::init;
use matrix::Matrix;

fn main() {
    println!("Reading training labels...");
    let train_labels = read_mnist_labels("data/mnist/train-labels-idx1-ubyte").unwrap();
    let train_labels_logits: Vec<Matrix<f32>> = train_labels.iter().cloned().map(|x| one_hot(x, 10)).collect();
    println!("Label count: {}", train_labels.len());

    println!("Reading training images...");
    let (rows, columns, train_images) = read_mnist_images("data/mnist/train-images-idx3-ubyte").unwrap();

    let ctx = matrix::Context::new();

    // Setup the graph. It's going to have 2 inputs, 3 hidden nodes in it's 1 hidden layer, and 1
    // output node
    let mut graph = Graph::new();

    //////////////////////////
    // Layer 1

    // Input.  1 batches of rows*columns inputs each.
    let input = graph.add_variable(&ctx, (1, rows*columns), vec![0.0; rows*columns]);
    // Weights for layer 1: [2 inputs x 3 nodes]
    let l1_w = graph.add_variable(&ctx, (rows*columns, 1000), init::Normal(0.001, 0.005));
    // Use matrix multiplication to do a fully connected layer
    let l1_mat_mul = graph.add_node(&ctx,
                                    MatMul::new(&ctx, (1, rows*columns), (rows*columns, 1000)),
                                    vec![input, l1_w],
                                    &[(1, 1000)]); // out shape: [5x2]*[2x3] = [5 batches x 3 outputs]
    // Grab VarIndex for l1_mat_mul's output
    let l1_mat_mul_out = l1_mat_mul.get(&graph).outputs[0];
    // 3 biases; one for each node in layer 1
    let l1_b = graph.add_variable(&ctx, (1, 1000), init::Normal(0.001, 0.005));
    // Here we add the biases to the matrix multiplication output
    let l1_biased = graph.add_node(&ctx,
                               Add::new(0),
                               vec![l1_mat_mul_out, l1_b],
                               &[(1, 1000)]);
    // Grab VarIndex for l1_biased's output
    let l1_biased_out = l1_biased.get(&graph).outputs[0];
    // Run the biased input*weight sums through an ReLU activation
    let l1_relu = graph.add_node(&ctx,
                                 Relu::new(),
                                 vec![l1_biased_out],
                                 &[(1, 1000)]);
    let l1_relu_out = l1_relu.get(&graph).outputs[0];

    //////////////////////////
    // Layer 2

    // Weights for layer 2: [3 inputs x 1 nodes]
    let l2_w = graph.add_variable(&ctx, (1000, 10), init::Normal(0.001, 0.005));
    // Fully connected layer 2. Use layer 1's output as layer 2's input
    let l2_mat_mul = graph.add_node(&ctx,
                                    MatMul::new(&ctx, (1, 1000), (1000, 10)),
                                    vec![l1_relu_out, l2_w],
                                    &[(1, 10)]); // out shape: [5x3]*[3x1] = [5 batches x 1 output]
    // Grab VarIndex for l2_mat_mul's output
    let l2_mat_mul_out = l2_mat_mul.get(&graph).outputs[0];
    // 1 bias for 1 output node
    let l2_b = graph.add_variable(&ctx, (1, 10), init::Normal(0.001, 0.005));
    // Here we add the bias to the matrix multiplication output
    let l2_biased = graph.add_node(&ctx,
                               Add::new(0),
                               vec![l2_mat_mul_out, l2_b],
                               &[(1, 10)]);
    // Grab VarIndex for l2_biased's output
    let l2_biased_out = l2_biased.get(&graph).outputs[0];
    // Run the biased input*weight sums through an ReLU activation
    let l2_relu = graph.add_node(&ctx,
                                 Relu::new(),
                                 vec![l2_biased_out],
                                 &[(1, 10)]);
    // Grab VarIndex for l2_relu's output
    let l2_relu_out = l2_relu.get(&graph).outputs[0];

    //////////////////////////
    // Loss

    // Add a variable for the training outputs: [5 batches x 1 output]
    let train_out = graph.add_variable(&ctx, (1, 10), vec![0.0; 10]);
    // Use mean squared error loss function
    let loss = graph.add_node(&ctx,
                              Mse::new(),
                              vec![l2_relu_out, train_out],
                              &[(1, 10)]);
    // Grab the VarIndex for loss's output
    let loss_out = loss.get(&graph).outputs[0];
    // Create a gradient to apply to the loss function
    let loss_d = graph.add_gradient(&ctx, loss, 0);

    ////////////////////////////////////////////////////////////////////////////////////////////////

    // We apply a gradient of -0.1 to the loss function
    let loss_d_cpu = Matrix::from_vec(1, 10, vec![-0.001; 10]);
    loss_d.get(&graph).set(&ctx, &loss_d_cpu);

    /////////////////////////
    // Run/Train the network
    let mut correct = 0;
    for epoch in 0..100000 {
        // Upload training data
        let train_sample = epoch%train_images.len();
        input.get(&graph).set(&ctx, &train_images[train_sample]);
        train_out.get(&graph).set(&ctx, &train_labels_logits[train_sample]);

        graph.run(&ctx);
        let out = l2_relu_out.get(&graph).get(&ctx);
        let out_d = l2_relu.get(&graph)
                           .out_grad[0]
                           .gradient()
                           .get(&graph)
                           .get(&ctx);
        let l = loss_out.get(&graph).get(&ctx);
        let l1_w_d = graph.get_input_gradient(l1_w).unwrap().get(&graph);
        let l2_w_d = graph.get_input_gradient(l2_w).unwrap().get(&graph);
        let l1_b_d = graph.get_input_gradient(l1_b).unwrap().get(&graph);
        let l2_b_d = graph.get_input_gradient(l2_b).unwrap().get(&graph);
        l1_w.get(&graph).add(&ctx, -1, &*l1_w_d, &*l1_w.get(&graph));
        l2_w.get(&graph).add(&ctx, -1, &*l2_w_d, &*l2_w.get(&graph));
        l1_b.get(&graph).add(&ctx, -1, &*l1_b_d, &*l1_b.get(&graph));
        l2_b.get(&graph).add(&ctx, -1, &*l2_b_d, &*l2_b.get(&graph));

        let (mut max_index, mut max_value) = (0, out[(0, 0)]);
        for (i, val) in out.buffer().iter().enumerate() {
            if *val > max_value {
                max_index = i;
                max_value = *val;
            }
        }

        if max_index == train_labels[train_sample] as usize {
            correct += 1;
        }

        if epoch % 1000 == 999 {
            println!("===================");
            println!("Epoch: {}", epoch);
            println!("out = {:?}", out);
            println!("out_d = {:?}", out_d);
            println!("loss = {:?}", l);
            println!("Accuracy: {}%", (correct as f32)/(1000 as f32) * 100.0);
            correct = 0;
        }
    }
}

fn read_mnist_labels<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
    use std::io::{Error, ErrorKind};

    let ref mut file = BufReader::new(File::open(path).unwrap());

    let magic = u32::from_be(try!(read_u32(file)));
    if magic != 2049 {
        return Err(Error::new(ErrorKind::Other,
                              format!("Invalid magic number. Got expect 2049, got {}",
                                      magic).as_ref()))
    }

    let label_count = u32::from_be(try!(read_u32(file)));

    let mut labels = Vec::with_capacity(label_count as usize);
    for _ in 0..label_count {
        labels.push(try!(read_u8(file)));
    }

    Ok(labels)
}

fn read_mnist_images<P: AsRef<Path>>(path: P) -> io::Result<(usize, usize, Vec<Matrix<f32>>)> {
    use std::io::{Error, ErrorKind};

    let ref mut file = BufReader::new(File::open(path).unwrap());

    let magic = u32::from_be(try!(read_u32(file)));
    if magic != 2051 {
        return Err(Error::new(ErrorKind::Other,
                              format!("Invalid magic number. Got expect 2051, got {}",
                                      magic).as_ref()))
    }

    let image_count = u32::from_be(try!(read_u32(file))) as usize;
    let rows = u32::from_be(try!(read_u32(file))) as usize;
    let columns = u32::from_be(try!(read_u32(file))) as usize;

    let mut images = Vec::with_capacity(image_count);
    for _ in 0..image_count {
        let mut pixel_buf = vec![0u8; rows*columns];
        try!(file.read_exact(pixel_buf.as_mut()));
        let matrix = Matrix::from_vec(rows, columns,
                                      pixel_buf.into_iter().map(|x| (x as f32)/255.0).collect());
        images.push(matrix);
    }

    Ok((rows, columns, images))
}

fn one_hot<N, M>(label: N, classes: N) -> Matrix<M>
    where usize: From<N>,
          M:     matrix::num::Num+Zero+One,
{
    let classes: usize = From::from(classes); // Cast class count to usize
    let label: usize = From::from(label); // Cast label to usize
    let mut buf: Vec<M> = vec![Zero::zero(); classes]; // Create array of zeroes
    buf[label] = One::one(); // Set the one-hot component
    Matrix::from_vec(1, buf.len(), buf) // Construct the matrix
}

fn read_u8<T: Read>(reader: &mut T) -> io::Result<u8> {
    use std::mem;

    let mut buf: [u8; 1] = [0];
    reader.read_exact(&mut buf).map(|_| {
        let data: u8 = unsafe { mem::transmute(buf) };
        data
    })
}

fn read_u32<T: Read>(reader: &mut T) -> io::Result<u32> {
    use std::mem;

    let mut buf: [u8; 4] = [0, 0, 0, 0];
    reader.read_exact(&mut buf).map(|_| {
        let data: u32 = unsafe { mem::transmute(buf) };
        data
    })
}
<commit_msg>MNIST validation<commit_after>#![feature(zero_one)]

extern crate deeplearn;
extern crate matrix;

use std::fs::File;
use std::io::{
    self,
    BufReader,
    Read,
};
use std::num::{Zero, One};
use std::path::Path;

use deeplearn::Graph;
use deeplearn::op::{Add, MatMul, Mse, Relu};
use deeplearn::init;
use matrix::Matrix;

fn main() {
    // Training data
    println!("Reading training labels...");
    let train_labels = read_mnist_labels("data/mnist/train-labels-idx1-ubyte", None).unwrap();
    let train_labels_logits: Vec<Matrix<f32>> = train_labels.iter().cloned().map(|x| one_hot(x, 10)).collect();
    println!("Label count: {}", train_labels.len());

    println!("Reading training images...");
    let (rows, columns, train_images) = read_mnist_images("data/mnist/train-images-idx3-ubyte", None).unwrap();

    // Validation data
    println!("Reading validation labels...");
    let val_labels = read_mnist_labels("data/mnist/t10k-labels-idx1-ubyte", Some(1000)).unwrap();
    let val_labels_logits: Vec<Matrix<f32>> = val_labels.iter().cloned().map(|x| one_hot(x, 10)).collect();
    println!("Label count: {}", train_labels.len());

    println!("Reading validation images...");
    let (_, _, val_images) = read_mnist_images("data/mnist/t10k-images-idx3-ubyte", Some(1000)).unwrap();

    let ctx = matrix::Context::new();

    // Setup the graph. It's going to have 2 inputs, 3 hidden nodes in it's 1 hidden layer, and 1
    // output node
    let mut graph = Graph::new();

    //////////////////////////
    // Layer 1

    // Input.  1 batches of rows*columns inputs each.
    let input = graph.add_variable(&ctx, (1, rows*columns), vec![0.0; rows*columns]);
    // Weights for layer 1: [2 inputs x 3 nodes]
    let l1_w = graph.add_variable(&ctx, (rows*columns, 1000), init::Normal(0.001, 0.005));
    // Use matrix multiplication to do a fully connected layer
    let l1_mat_mul = graph.add_node(&ctx,
                                    MatMul::new(&ctx, (1, rows*columns), (rows*columns, 1000)),
                                    vec![input, l1_w],
                                    &[(1, 1000)]); // out shape: [5x2]*[2x3] = [5 batches x 3 outputs]
    // Grab VarIndex for l1_mat_mul's output
    let l1_mat_mul_out = l1_mat_mul.get(&graph).outputs[0];
    // 3 biases; one for each node in layer 1
    let l1_b = graph.add_variable(&ctx, (1, 1000), init::Normal(0.001, 0.005));
    // Here we add the biases to the matrix multiplication output
    let l1_biased = graph.add_node(&ctx,
                               Add::new(0),
                               vec![l1_mat_mul_out, l1_b],
                               &[(1, 1000)]);
    // Grab VarIndex for l1_biased's output
    let l1_biased_out = l1_biased.get(&graph).outputs[0];
    // Run the biased input*weight sums through an ReLU activation
    let l1_relu = graph.add_node(&ctx,
                                 Relu::new(),
                                 vec![l1_biased_out],
                                 &[(1, 1000)]);
    let l1_relu_out = l1_relu.get(&graph).outputs[0];

    //////////////////////////
    // Layer 2

    // Weights for layer 2: [3 inputs x 1 nodes]
    let l2_w = graph.add_variable(&ctx, (1000, 10), init::Normal(0.001, 0.005));
    // Fully connected layer 2. Use layer 1's output as layer 2's input
    let l2_mat_mul = graph.add_node(&ctx,
                                    MatMul::new(&ctx, (1, 1000), (1000, 10)),
                                    vec![l1_relu_out, l2_w],
                                    &[(1, 10)]); // out shape: [5x3]*[3x1] = [5 batches x 1 output]
    // Grab VarIndex for l2_mat_mul's output
    let l2_mat_mul_out = l2_mat_mul.get(&graph).outputs[0];
    // 1 bias for 1 output node
    let l2_b = graph.add_variable(&ctx, (1, 10), init::Normal(0.001, 0.005));
    // Here we add the bias to the matrix multiplication output
    let l2_biased = graph.add_node(&ctx,
                               Add::new(0),
                               vec![l2_mat_mul_out, l2_b],
                               &[(1, 10)]);
    // Grab VarIndex for l2_biased's output
    let l2_biased_out = l2_biased.get(&graph).outputs[0];
    // Run the biased input*weight sums through an ReLU activation
    let l2_relu = graph.add_node(&ctx,
                                 Relu::new(),
                                 vec![l2_biased_out],
                                 &[(1, 10)]);
    // Grab VarIndex for l2_relu's output
    let l2_relu_out = l2_relu.get(&graph).outputs[0];

    //////////////////////////
    // Loss

    // Add a variable for the training outputs: [5 batches x 1 output]
    let train_out = graph.add_variable(&ctx, (1, 10), vec![0.0; 10]);
    // Use mean squared error loss function
    let loss = graph.add_node(&ctx,
                              Mse::new(),
                              vec![l2_relu_out, train_out],
                              &[(1, 10)]);
    // Grab the VarIndex for loss's output
    let loss_out = loss.get(&graph).outputs[0];
    // Create a gradient to apply to the loss function
    let loss_d = graph.add_gradient(&ctx, loss, 0);

    ////////////////////////////////////////////////////////////////////////////////////////////////

    // We apply a gradient of -0.1 to the loss function
    let loss_d_cpu = Matrix::from_vec(1, 10, vec![-0.001; 10]);
    loss_d.get(&graph).set(&ctx, &loss_d_cpu);

    /////////////////////////
    // Train the network
    let mut correct = 0;
    for epoch in 0..60000 {
        // Upload training data
        let train_sample = epoch%train_images.len();
        input.get(&graph).set(&ctx, &train_images[train_sample]);
        train_out.get(&graph).set(&ctx, &train_labels_logits[train_sample]);

        graph.run(&ctx);
        let out = l2_relu_out.get(&graph).get(&ctx);
        let out_d = l2_relu.get(&graph)
                           .out_grad[0]
                           .gradient()
                           .get(&graph)
                           .get(&ctx);
        let l = loss_out.get(&graph).get(&ctx);
        let l1_w_d = graph.get_input_gradient(l1_w).unwrap().get(&graph);
        let l2_w_d = graph.get_input_gradient(l2_w).unwrap().get(&graph);
        let l1_b_d = graph.get_input_gradient(l1_b).unwrap().get(&graph);
        let l2_b_d = graph.get_input_gradient(l2_b).unwrap().get(&graph);
        l1_w.get(&graph).add(&ctx, -1, &*l1_w_d, &*l1_w.get(&graph));
        l2_w.get(&graph).add(&ctx, -1, &*l2_w_d, &*l2_w.get(&graph));
        l1_b.get(&graph).add(&ctx, -1, &*l1_b_d, &*l1_b.get(&graph));
        l2_b.get(&graph).add(&ctx, -1, &*l2_b_d, &*l2_b.get(&graph));

        let (mut max_index, mut max_value) = (0, out[(0, 0)]);
        for (i, val) in out.buffer().iter().enumerate() {
            if *val > max_value {
                max_index = i;
                max_value = *val;
            }
        }

        if max_index == train_labels[train_sample] as usize {
            correct += 1;
        }

        if epoch % 1000 == 999 {
            println!("===================");
            println!("Epoch: {}", epoch);
            println!("out = {:?}", out);
            println!("out_d = {:?}", out_d);
            println!("loss = {:?}", l);
            println!("Accuracy: {}%", (correct as f32)/(1000 as f32) * 100.0);
            correct = 0;
        }
    }

    /////////////////////////
    // Validate the network
    println!("#######################################");
    println!("Validating");
    let mut correct = 0;
    for epoch in 0..1000 {
        // Upload training data
        let train_sample = epoch%val_images.len();
        input.get(&graph).set(&ctx, &val_images[train_sample]);
        train_out.get(&graph).set(&ctx, &val_labels_logits[train_sample]);

        graph.run(&ctx);
        let out = l2_relu_out.get(&graph).get(&ctx);
        let out_d = l2_relu.get(&graph)
                           .out_grad[0]
                           .gradient()
                           .get(&graph)
                           .get(&ctx);
        let l = loss_out.get(&graph).get(&ctx);

        let (mut max_index, mut max_value) = (0, out[(0, 0)]);
        for (i, val) in out.buffer().iter().enumerate() {
            if *val > max_value {
                max_index = i;
                max_value = *val;
            }
        }

        if max_index == val_labels[train_sample] as usize {
            correct += 1;
        }

        if epoch % 1000 == 999 {
            println!("===================");
            println!("Epoch: {}", epoch);
            println!("out = {:?}", out);
            println!("out_d = {:?}", out_d);
            println!("loss = {:?}", l);
            println!("Accuracy: {}%", (correct as f32)/(1000 as f32) * 100.0);
            correct = 0;
        }
    }
}

fn read_mnist_labels<P: AsRef<Path>>(path: P, num_samples: Option<usize>) -> io::Result<Vec<u8>> {
    use std::io::{Error, ErrorKind};

    let ref mut file = BufReader::new(File::open(path).unwrap());

    let magic = u32::from_be(try!(read_u32(file)));
    if magic != 2049 {
        return Err(Error::new(ErrorKind::Other,
                              format!("Invalid magic number. Got expect 2049, got {}",
                                      magic).as_ref()))
    }

    let label_count = u32::from_be(try!(read_u32(file)));

    let mut labels = Vec::with_capacity(label_count as usize);
    for i in 0..label_count {
        if let Some(num_samples) = num_samples {
            if i as usize > num_samples {
                break;
            }
        }
        labels.push(try!(read_u8(file)));
    }

    Ok(labels)
}

fn read_mnist_images<P: AsRef<Path>>(path: P, num_samples: Option<usize>) -> io::Result<(usize, usize, Vec<Matrix<f32>>)> {
    use std::io::{Error, ErrorKind};

    let ref mut file = BufReader::new(File::open(path).unwrap());

    let magic = u32::from_be(try!(read_u32(file)));
    if magic != 2051 {
        return Err(Error::new(ErrorKind::Other,
                              format!("Invalid magic number. Got expect 2051, got {}",
                                      magic).as_ref()))
    }

    let image_count = u32::from_be(try!(read_u32(file))) as usize;
    let rows = u32::from_be(try!(read_u32(file))) as usize;
    let columns = u32::from_be(try!(read_u32(file))) as usize;

    let mut images = Vec::with_capacity(image_count);
    for i in 0..image_count {
        if let Some(num_samples) = num_samples {
            if i as usize > num_samples {
                break;
            }
        }
        let mut pixel_buf = vec![0u8; rows*columns];
        try!(file.read_exact(pixel_buf.as_mut()));
        let matrix = Matrix::from_vec(rows, columns,
                                      pixel_buf.into_iter().map(|x| (x as f32)/255.0).collect());
        images.push(matrix);
    }

    Ok((rows, columns, images))
}

fn one_hot<N, M>(label: N, classes: N) -> Matrix<M>
    where usize: From<N>,
          M:     matrix::num::Num+Zero+One,
{
    let classes: usize = From::from(classes); // Cast class count to usize
    let label: usize = From::from(label); // Cast label to usize
    let mut buf: Vec<M> = vec![Zero::zero(); classes]; // Create array of zeroes
    buf[label] = One::one(); // Set the one-hot component
    Matrix::from_vec(1, buf.len(), buf) // Construct the matrix
}

fn read_u8<T: Read>(reader: &mut T) -> io::Result<u8> {
    use std::mem;

    let mut buf: [u8; 1] = [0];
    reader.read_exact(&mut buf).map(|_| {
        let data: u8 = unsafe { mem::transmute(buf) };
        data
    })
}

fn read_u32<T: Read>(reader: &mut T) -> io::Result<u32> {
    use std::mem;

    let mut buf: [u8; 4] = [0, 0, 0, 0];
    reader.read_exact(&mut buf).map(|_| {
        let data: u32 = unsafe { mem::transmute(buf) };
        data
    })
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate twitter_api as twitter;
extern crate rustc_serialize as rustc_serialize;
extern crate oauth_client as oauth;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::path::PathBuf;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const TWITTER_CONF_FILENAME: &'static str = ".twitter.conf";

fn get_home_dir() -> PathBuf{
    match env::home_dir() {
        Some(p) => p,
        None => {
            panic!("Impossible to get your home dir!");
        }
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read(path_file : &Path) -> Option<Config> {
        let mut file = match File::open(path_file) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self, path_file : &Path) {
        let mut file = match OpenOptions::new().write(true).open(path_file) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = write!(&mut file, "{}\n", &json::encode(self).unwrap());
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line).unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, &pin);

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, &status);
}

<commit_msg>examples/tweet.rs : new function implemented for Config, which allows to create the twitter configuration file if he does not exists<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate twitter_api as twitter;
extern crate rustc_serialize as rustc_serialize;
extern crate oauth_client as oauth;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::path::PathBuf;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const TWITTER_CONF_FILENAME: &'static str = ".twitter.conf";

fn get_home_dir() -> PathBuf{
    match env::home_dir() {
        Some(p) => p,
        None => {
            panic!("Impossible to get your home dir!");
        }
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read(path_file : &Path) -> Option<Config> {
        let mut file = match File::open(path_file) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self, path_file : &Path) {
        let mut file = match OpenOptions::new().write(true).open(path_file) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = write!(&mut file, "{}\n", &json::encode(self).unwrap());
    }

    pub fn create(path_file : &Path) {
        match File::create(path_file) {
            Ok(_) => println!("File created!"),
            Err(_) => panic!("Problem to create the file...\nProgram aborted!")
        }
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line).unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, &pin);

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, &status);
}

<|endoftext|>


<commit_before>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec {
            t: libc::timespec { tv_sec: 0, tv_nsec: 0 },
        }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
                              (self.t.tv_nsec - other.t.tv_nsec) as u32)
            } else {
                Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
                              self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
                              other.t.tv_nsec as u32)
            })
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec {
            t: libc::timespec {
                tv_sec: secs,
                tv_nsec: nsec as _,
            },
        })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec {
            t: libc::timespec {
                tv_sec: secs,
                tv_nsec: nsec as _,
            },
        })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H : Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::mem;
    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::NSEC_PER_SEC;
    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime {
        t: Timespec::zero(),
    };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant {
                t: self.t.checked_add(checked_dur2intervals(other)?)?,
            })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant {
                t: self.t.checked_sub(checked_dur2intervals(other)?)?,
            })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval {
                tv_sec: 0,
                tv_usec: 0,
            };
            cvt(unsafe {
                libc::gettimeofday(&mut s, ptr::null_mut())
            }).unwrap();
            return SystemTime::from(s)
        }

        pub fn sub_time(&self, other: &SystemTime)
                        -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
             .field("tv_sec", &self.t.t.tv_sec)
             .field("tv_nsec", &self.t.t.tv_nsec)
             .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos = dur.as_secs()
            .checked_mul(NSEC_PER_SEC)?
            .checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        static mut INFO: mach_timebase_info = mach_timebase_info {
            numer: 0,
            denom: 0,
        };
        static STATE: AtomicUsize = AtomicUsize::new(0);

        unsafe {
            // If a previous thread has filled in this global state, use that.
            if STATE.load(SeqCst) == 2 {
                return INFO;
            }

            // ... otherwise learn for ourselves ...
            let mut info = mem::zeroed();
            extern "C" {
                fn mach_timebase_info(info: mach_timebase_info_t)
                                      -> kern_return_t;
            }

            mach_timebase_info(&mut info);

            // ... and attempt to be the one thread that stores it globally for
            // all other threads
            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
                INFO = info;
                STATE.store(2, SeqCst);
            }
            return info;
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime {
        t: Timespec::zero(),
    };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant {
                t: Timespec::zero(),
            }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) ||
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) ||
            false // last clause, used so `||` is always trailing above
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
             .field("tv_sec", &self.t.t.tv_sec)
             .field("tv_nsec", &self.t.t.tv_nsec)
             .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime)
                        -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
             .field("tv_sec", &self.t.t.tv_sec)
             .field("tv_nsec", &self.t.t.tv_nsec)
             .finish()
        }
    }

    #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
    pub type clock_t = libc::c_int;
    #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec {
            t: libc::timespec {
                tv_sec: 0,
                tv_nsec: 0,
            }
        };
        cvt(unsafe {
            libc::clock_gettime(clock, &mut t.t)
        }).unwrap();
        t
    }
}
<commit_msg>Add Fuchsia to actually_monotonic<commit_after>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec {
            t: libc::timespec { tv_sec: 0, tv_nsec: 0 },
        }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
                              (self.t.tv_nsec - other.t.tv_nsec) as u32)
            } else {
                Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
                              self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
                              other.t.tv_nsec as u32)
            })
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec {
            t: libc::timespec {
                tv_sec: secs,
                tv_nsec: nsec as _,
            },
        })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec {
            t: libc::timespec {
                tv_sec: secs,
                tv_nsec: nsec as _,
            },
        })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H : Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::mem;
    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::NSEC_PER_SEC;
    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime {
        t: Timespec::zero(),
    };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant {
                t: self.t.checked_add(checked_dur2intervals(other)?)?,
            })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant {
                t: self.t.checked_sub(checked_dur2intervals(other)?)?,
            })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval {
                tv_sec: 0,
                tv_usec: 0,
            };
            cvt(unsafe {
                libc::gettimeofday(&mut s, ptr::null_mut())
            }).unwrap();
            return SystemTime::from(s)
        }

        pub fn sub_time(&self, other: &SystemTime)
                        -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
             .field("tv_sec", &self.t.t.tv_sec)
             .field("tv_nsec", &self.t.t.tv_nsec)
             .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos = dur.as_secs()
            .checked_mul(NSEC_PER_SEC)?
            .checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        static mut INFO: mach_timebase_info = mach_timebase_info {
            numer: 0,
            denom: 0,
        };
        static STATE: AtomicUsize = AtomicUsize::new(0);

        unsafe {
            // If a previous thread has filled in this global state, use that.
            if STATE.load(SeqCst) == 2 {
                return INFO;
            }

            // ... otherwise learn for ourselves ...
            let mut info = mem::zeroed();
            extern "C" {
                fn mach_timebase_info(info: mach_timebase_info_t)
                                      -> kern_return_t;
            }

            mach_timebase_info(&mut info);

            // ... and attempt to be the one thread that stores it globally for
            // all other threads
            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
                INFO = info;
                STATE.store(2, SeqCst);
            }
            return info;
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime {
        t: Timespec::zero(),
    };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant {
                t: Timespec::zero(),
            }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) ||
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) ||
            cfg!(target_os = "fuchsia") ||
            false // last clause, used so `||` is always trailing above
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
             .field("tv_sec", &self.t.t.tv_sec)
             .field("tv_nsec", &self.t.t.tv_nsec)
             .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime)
                        -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
             .field("tv_sec", &self.t.t.tv_sec)
             .field("tv_nsec", &self.t.t.tv_nsec)
             .finish()
        }
    }

    #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
    pub type clock_t = libc::c_int;
    #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec {
            t: libc::timespec {
                tv_sec: 0,
                tv_nsec: 0,
            }
        };
        cvt(unsafe {
            libc::clock_gettime(clock, &mut t.t)
        }).unwrap();
        t
    }
}
<|endoftext|>