shareable 0.1.1

Thread shareable objects using the minimal amount of synchronization.
Documentation
/* Copyright 2016 Joshua Gentry
 *
 * 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.
 */
#[cfg(not(target_pointer_width = "32"))]
use std::mem::transmute;
use std::sync::Arc;

#[cfg(target_pointer_width = "32")]
use std::sync::Mutex;

#[cfg(not(target_pointer_width = "32"))]
use std::sync::atomic::{AtomicUsize, Ordering};

//*************************************************************************************************
/// Shareable i64 data element.
///
/// If the architecture is 64 bit then the value is saved in an atomic otherwise a mutex is used.
///
/// # Examples
///
/// ```
/// use std::sync::mpsc;
/// use std::thread;
/// use shareable::SharedI64;
///
/// let value1 = SharedI64::new(63);
/// let value2 = value1.clone();
///
/// let (tx, rx) = mpsc::channel();
///
/// let thread = thread::spawn(move || {
///     rx.recv();
///     assert_eq!(value2.get(), 31);
/// });
///
/// value1.set(31);
///
/// tx.send(());
/// thread.join().unwrap();
/// ```
#[derive(Clone)]
pub struct SharedI64
{
    //---------------------------------------------------------------------------------------------
    /// The internal data element.
    #[cfg(target_pointer_width = "32")]
    data : Arc<Mutex<i64>>,
    #[cfg(not(target_pointer_width = "32"))]
    data : Arc<AtomicUsize>
}

#[cfg(target_pointer_width = "32")]
impl SharedI64
{
    //********************************************************************************************
    /// Construct a new instance of the object.
    pub fn new(
        value : i64
        ) -> SharedI64
    {
        SharedI64 {
            data : Arc::new(Mutex::new(value))
        }
    }

    //********************************************************************************************
    /// Set the value of the object.
    pub fn set(
        &self,
        value : i64
        )
    {
        let mut data = self.data.lock().unwrap();

        *data = value;
    }

    //********************************************************************************************
    /// Returns the value of the object.
    pub fn get(&self) -> i64
    {
        let data = self.data.lock().unwrap();

        *data
    }
}

#[cfg(not(target_pointer_width = "32"))]
impl SharedI64
{
    //********************************************************************************************
    /// Construct a new instance of the object.
    pub fn new(
        value : i64
        ) -> SharedI64
    {
        unsafe {
            SharedI64 {
                data : Arc::new(AtomicUsize::new(transmute(value)))
            }
        }
    }

    //********************************************************************************************
    /// Set the value of the object.
    pub fn set(
        &self,
        value : i64
        )
    {
        unsafe {
            self.data.store(transmute(value), Ordering::Relaxed)
        }
    }

    //********************************************************************************************
    /// Returns the value of the object.
    pub fn get(&self) -> i64
    {
        unsafe {
            transmute(self.data.load(Ordering::Relaxed))
        }
    }
}

use std::fmt::{Debug, Display, Formatter, Error};

impl Debug for SharedI64
{
    //*********************************************************************************************
    /// Implementation of Debug.
    fn fmt(
        &self,
        f : &mut Formatter
        ) -> Result<(), Error>
    {
        write!(f, "{:?}", self.get())
    }
}

impl Display for SharedI64
{
    //*********************************************************************************************
    /// Implementation of Display.
    fn fmt(
        &self,
        f : &mut Formatter
        ) -> Result<(), Error>
    {
        write!(f, "{}", self.get())
    }
}

#[cfg(test)]
mod tests
{

    //*********************************************************************************************
    /// Test that get/set work with only 1 instance.
    #[test]
    fn test_single()
    {
        let test = super::SharedI64::new(-79);

        assert_eq!(test.get(), -79);
        test.set(41);
        assert_eq!(test.get(), 41);
    }

    //*********************************************************************************************
    /// Test that get/set work with multiple instances.
    #[test]
    fn test_multiple()
    {
        let test1 = super::SharedI64::new(-79);
        let test2 = test1.clone();
        let test3 = test2.clone();

        assert_eq!(test1.get(), -79);
        assert_eq!(test2.get(), -79);
        assert_eq!(test3.get(), -79);

        test1.set(51);

        assert_eq!(test1.get(), 51);
        assert_eq!(test2.get(), 51);
        assert_eq!(test3.get(), 51);

        test2.set(31);

        assert_eq!(test1.get(), 31);
        assert_eq!(test2.get(), 31);
        assert_eq!(test3.get(), 31);

        test3.set(-11);

        assert_eq!(test1.get(), -11);
        assert_eq!(test2.get(), -11);
        assert_eq!(test3.get(), -11);
    }
}