<commit_before>#![feature(const_fn)]
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

/// A cell holding values protected by an atomic lock.
///
/// This cell is designed to hold values that implement `Clone` and to
/// distribute them to threads as needed. It may be instantiated as
/// a `static` value.
///
/// This cell is optimized for low contention.
impl<T> AtomicCell<T> where T: Clone {
    pub const fn new() -> Self {
        AtomicCell {
            ptr: AtomicPtr::new(std::ptr::null_mut()),
            lock: AtomicBool::new(true)
        }
    }

    pub fn set(&self, value: T) {
        self.swap(Some(Box::new(value)));
    }

    pub fn unset(&self) {
        self.swap(None);
    }

    pub fn swap(&self, value: Option<Box<T>>) -> Option<Box<T>> {
        let new_ptr = self.ptr_from_opt(value);
        // We are now the owner of `value` as a pointer. From this
        // point, we are in charge of dropping it manually.
        self.with_lock(|| {
            let old_ptr = self.ptr.swap(new_ptr, Ordering::Relaxed);
            self.opt_from_ptr(old_ptr)
        })
    }

    fn ptr_from_opt(&self, value: Option<Box<T>>) -> *mut T {
        match value {
            None => std::ptr::null_mut(),
            Some(b) => Box::into_raw(b)
        }
    }

    fn opt_from_ptr(&self, ptr: *mut T) -> Option<Box<T>> {
        if ptr.is_null() {
            None
        } else {
            unsafe { Some(Box::from_raw(ptr)) }
        }
    }

    fn with_lock<F, R>(&self, f: F) -> R where F: FnOnce(/*&mut AtomicCell<T>*/) -> R {
        loop {
            // Attempt to acquire the lock.
            // This data structure is designed for low contention, so we can use
            // an atomic spinlock.
            let owning = self.lock.compare_and_swap(/*must be available*/true,
                                                    /*mark as unavailable*/false, Ordering::Relaxed); // FIXME: Check ordering.
            if owning {
                // We are now the owner of the lock.
                // We must be very careful not to panic becore we have released the lock.
                let result = f();

                // Release the lock.
                self.lock.swap(true, Ordering::Relaxed);

                return result;
            }
        }
    }

    pub fn get(&self) -> Option<Box<T>> {
        self.with_lock(|| {
            let ptr = self.ptr.load(Ordering::Relaxed).clone();
            // The original. We must be very careful to not drop it.
            let original = self.opt_from_ptr(ptr);

            let result = original.clone(); // FIXME: What if this panics? Do we need poisoning?

            // Eat back `original` to ensure that it is not dropped.
            self.ptr_from_opt(original);
            result
        })
    }
}

pub struct AtomicCell<T> where T: Clone {
    ptr: AtomicPtr<T>,
    lock: AtomicBool
}

unsafe impl<T> Sync for AtomicCell<T> where T: Clone + Send {
}

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

    use std::ops::Add;
    use std::sync::mpsc::{channel, Sender};
    use std::thread;

    static CELL: AtomicCell<Sender<u32>> = AtomicCell::new();

    #[test]
    fn test_channels() {
        let (tx, rx) = channel();
        CELL.set(tx);
        for i in 0..10 {
            thread::spawn(move || {
                let tx = CELL.get().unwrap();
                tx.send(i).unwrap();
            });
        }
        assert_eq!(rx.iter().take(10).fold(0, Add::add), 45);
    }

    #[test]
    fn test_empty() {
        let (tx, rx) = channel();
        CELL.set(tx);
        for i in 0..10 {
            thread::spawn(move || {
                let tx = CELL.get().unwrap();
                tx.send(i).unwrap();
            });
        }
        assert_eq!(rx.iter().take(10).fold(0, Add::add), 45);
    }

}
<commit_msg>More doc<commit_after>#![feature(const_fn)]
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

/// A cell holding values protected by an atomic lock.
///
/// This cell is designed to hold values that implement `Clone` and to
/// distribute them to threads as needed. It may be instantiated as
/// a `static` value.
///
/// This cell is optimized for low contention.
///
/// FIXME: Resolve the matter of dropping.
///
/// FIXME: May need to poison the cell in case of panic in `clone`.
impl<T> AtomicCell<T> where T: Clone {
    ///
    /// Create an empty cell.
    ///
    pub const fn new() -> Self {
        AtomicCell {
            ptr: AtomicPtr::new(std::ptr::null_mut()),
            lock: AtomicBool::new(true)
        }
    }

    ///
    /// Put a value in the cell.
    ///
    /// If there was a previous value, it is dropped.
    ///
    /// Argument `value` will **not** be dropped automatically. You should
    /// call `set`, `unset` or `swap` to ensure that it is dropped.
    ///
    /// See also `swap`.
    ///
    /// # Performance
    ///
    /// This method requires acquiring an atomic lock. If contention
    /// is low, it should be very fast. However, in case of high
    /// contention, performance may degrade considerably.
    ///
    pub fn set(&self, value: T) {
        self.swap(Some(Box::new(value)));
    }

    ///
    /// Remove whichever value is in the cell.
    ///
    /// If there was a previous value, it is dropped.
    ///
    /// Argument `value` will **not** be dropped automatically. You should
    /// call `set`, `unset` or `swap` to ensure that it is dropped.
    ///
    /// # Performance
    ///
    /// This method requires acquiring an atomic lock. If contention
    /// is low, it should be very fast. However, in case of high
    /// contention, performance may degrade considerably.
    ///
    pub fn unset(&self) {
        self.swap(None);
    }

    ///
    /// Get a clone of the current value in the cell.
    ///
    /// # Performance
    ///
    /// This method requires acquiring an atomic lock. If contention
    /// is low, it should be very fast. However, in case of high
    /// contention, performance may degrade considerably.
    ///
    /// # Panics
    ///
    /// If the `clone` method panics, this will cause a panic.
    ///
    /// FIXME: In the current state of things, a panic in the call to
    /// `clone` will also render the cell unusable forever (the lock
    /// can never be acquired).
    ///
    pub fn get(&self) -> Option<Box<T>> {
        self.with_lock(|| {
            let ptr = self.ptr.load(Ordering::Relaxed).clone();
            // The original. We must be very careful to not drop it.
            let original = self.opt_from_ptr(ptr);

            let result = original.clone(); // FIXME: What if this panics? Do we need poisoning?

            // Eat back `original` to ensure that it is not dropped.
            self.ptr_from_opt(original);
            result
        })
    }

    ///
    /// Replace the value currently in the cell with another value.
    ///
    /// # Performance
    ///
    /// This method requires acquiring an atomic lock. If contention
    /// is low, it should be very fast. However, in case of high
    /// contention, performance may degrade considerably.
    ///
    pub fn swap(&self, value: Option<Box<T>>) -> Option<Box<T>> {
        let new_ptr = self.ptr_from_opt(value);
        // We are now the owner of `value` as a pointer. From this
        // point, we are in charge of dropping it manually.
        self.with_lock(|| {
            let old_ptr = self.ptr.swap(new_ptr, Ordering::Relaxed);
            self.opt_from_ptr(old_ptr)
        })
    }

    fn ptr_from_opt(&self, value: Option<Box<T>>) -> *mut T {
        match value {
            None => std::ptr::null_mut(),
            Some(b) => Box::into_raw(b)
        }
    }

    fn opt_from_ptr(&self, ptr: *mut T) -> Option<Box<T>> {
        if ptr.is_null() {
            None
        } else {
            unsafe { Some(Box::from_raw(ptr)) }
        }
    }

    ///
    /// Acquire the lock.
    ///
    /// We use an atomic spinlock.
    ///
    /// # Safety
    ///
    /// If `f` panics, the lock becomes impossible to
    /// acquire. Ever. You have been warned.
    ///
    fn with_lock<F, R>(&self, f: F) -> R where F: FnOnce() -> R {
        loop {
            // Attempt to acquire the lock.
            // This data structure is designed for low contention, so we can use
            // an atomic spinlock.
            let owning = self.lock.compare_and_swap(/*must be available*/true,
                                                    /*mark as unavailable*/false, Ordering::Relaxed); // FIXME: Check ordering.
            if owning {
                // We are now the owner of the lock.
                // We must be very careful not to panic becore we have released the lock.
                let result = f();

                // Release the lock.
                self.lock.swap(true, Ordering::Relaxed);

                return result;
            }
        }
    }
}

pub struct AtomicCell<T> where T: Clone {
    ptr: AtomicPtr<T>,
    lock: AtomicBool
}

unsafe impl<T> Sync for AtomicCell<T> where T: Clone + Send {
}

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

    use std::ops::Add;
    use std::sync::mpsc::{channel, Sender};
    use std::thread;

    // Test that we can allocate a cell and use it to distribute value
    // to several threads.
    static CELL: AtomicCell<Sender<u32>> = AtomicCell::new();
    #[test]
    fn test_channels() {
        let (tx, rx) = channel();
        CELL.set(tx);
        for i in 0..10 {
            thread::spawn(move || {
                let tx = CELL.get().unwrap();
                tx.send(i).unwrap();
            });
        }
        assert_eq!(rx.iter().take(10).fold(0, Add::add), 45);
    }

    // Test that `get()` on an empty cell returns `None`.
    static CELL2: AtomicCell<u32> = AtomicCell::new();
    #[test]
    fn test_empty() {
        for _ in 0..10 {
            thread::spawn(move || {
                assert_eq!(CELL2.get(), None);
            });
        }
        assert_eq!(CELL2.get(), None);
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write, Read, BufRead};
use std::convert::{AsRef, AsMut};
use std::ops::Deref;
use std::ops::DerefMut;

pub use Either::{Left, Right};

/// `Either` represents an alternative holding one value out of
/// either of the two possible values.
///
/// `Either` treats the two cases `Left` and `Right` equally, with
/// no priority.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Either<L, R> {
    /// A value of type `L`.
    Left(L),
    /// A value of type `R`.
    Right(R),
}

macro_rules! either {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref $inner) => $result,
            Either::Right(ref $inner) => $result,
        }
    )
}

macro_rules! either_mut {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref mut $inner) => $result,
            Either::Right(ref mut $inner) => $result,
        }
    )
}

impl<L, R> Either<L, R> {
    pub fn is_left(&self) -> bool {
        match *self {
            Left(_) => true,
            Right(_) => false,
        }
    }

    pub fn is_right(&self) -> bool {
        !self.is_left()
    }

    pub fn left(self) -> Option<L> {
        match self {
            Left(l) => Some(l),
            Right(_) => None,
        }
    }

    pub fn right(self) -> Option<R> {
        match self {
            Left(_) => None,
            Right(r) => Some(r),
        }
    }

    pub fn as_ref(&self) -> Either<&L, &R> {
        match *self {
            Left(ref inner) => Left(inner),
            Right(ref inner) => Right(inner),
        }
    }

    pub fn as_mut(&mut self) -> Either<&mut L, &mut R> {
        match *self {
            Left(ref mut inner) => Left(inner),
            Right(ref mut inner) => Right(inner),
        }
    }

    pub fn flip(self) -> Either<R, L> {
        match self {
            Left(l) => Right(l),
            Right(r) => Left(r),
        }
    }
}

/// Convert from `Result` to `Either` with `Ok => Right` and `Err => Left`.
impl<L, R> From<Result<R, L>> for Either<L, R> {
    fn from(r: Result<R, L>) -> Self {
        match r {
            Err(e) => Left(e),
            Ok(o) => Right(o),
        }
    }
}

/// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`.
impl<L, R> Into<Result<R, L>> for Either<L, R> {
    fn into(self) -> Result<R, L> {
        match self {
            Left(l) => Err(l),
            Right(r) => Ok(r),
        }
    }
}

/// `Either<L, R>` is an iterator if both `L` and `R` are iterators.
impl<L, R> Iterator for Either<L, R>
    where L: Iterator, R: Iterator<Item=L::Item>
{
    type Item = L::Item;

    fn next(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        either!(*self, inner => inner.size_hint())
    }
}

impl<L, R> DoubleEndedIterator for Either<L, R>
    where L: DoubleEndedIterator, R: DoubleEndedIterator<Item=L::Item>
{
    fn next_back(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next_back())
    }
}

impl<L, R> ExactSizeIterator for Either<L, R>
    where L: ExactSizeIterator, R: ExactSizeIterator<Item=L::Item>
{
}

/// `Either<L, R>` implements `Read` if both `L` and `R` do.
impl<L, R> Read for Either<L, R>
    where L: Read, R: Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read(buf))
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read_to_end(buf))
    }
}

impl<L, R> BufRead for Either<L, R>
    where L: BufRead, R: BufRead
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        either_mut!(*self, inner => inner.fill_buf())
    }

    fn consume(&mut self, amt: usize) {
        either_mut!(*self, inner => inner.consume(amt))
    }
}

/// `Either<L, R>` implements `Write` if both `L` and `R` do.
impl<L, R> Write for Either<L, R>
    where L: Write, R: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        either_mut!(*self, inner => inner.flush())
    }
}

impl<L, R, Target> AsRef<Target> for Either<L, R>
    where L: AsRef<Target>, R: AsRef<Target>
{
    fn as_ref(&self) -> &Target {
        either!(*self, inner => inner.as_ref())
    }
}

impl<L, R, Target> AsMut<Target> for Either<L, R>
    where L: AsMut<Target>, R: AsMut<Target>
{
    fn as_mut(&mut self) -> &mut Target {
        either_mut!(*self, inner => inner.as_mut())
    }
}

impl<L, R> Deref for Either<L, R>
    where L: Deref, R: Deref<Target=L::Target>
{
    type Target = L::Target;

    fn deref(&self) -> &Self::Target {
        either!(*self, inner => &*inner)
    }
}

impl<L, R> DerefMut for Either<L, R>
    where L: DerefMut, R: DerefMut<Target=L::Target>
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        either_mut!(*self, inner => &mut *inner)
    }
}

#[test]
fn basic() {
    let mut e = Left(2);
    let r = Right(2);
    assert_eq!(e, Left(2));
    e = r;
    assert_eq!(e, Right(2));
    assert_eq!(e.left(), None);
    assert_eq!(e.right(), Some(2));
    assert_eq!(e.as_ref().right(), Some(&2));
    assert_eq!(e.as_mut().right(), Some(&mut 2));
}

#[test]
fn deref() {
    fn is_str(_: &str) {}
    let value: Either<String, &str> = Left(String::from("test"));
    is_str(&*value);
}

#[test]
fn iter() {
    let x = 3;
    let mut iter = match x {
        1...3 => Left(0..10),
        _ => Right(17..),
    };

    assert_eq!(iter.next(), Some(0));
    assert_eq!(iter.count(), 9);
}

#[test]
fn read_write() {
    use std::io;

    let use_stdio = false;
    let mockdata = [0xff; 256];

    let mut reader = if use_stdio {
        Left(io::stdin())
    } else {
        Right(&mockdata[..])
    };

    let mut buf = [0u8; 16];
    assert_eq!(reader.read(&mut buf).unwrap(), buf.len());
    assert_eq!(&buf, &mockdata[..buf.len()]);

    let mut mockbuf = [0u8; 256];
    let mut writer = if use_stdio {
        Left(io::stdout())
    } else {
        Right(&mut mockbuf[..])
    };

    let buf = [1u8; 16];
    assert_eq!(writer.write(&buf).unwrap(), buf.len());
}
<commit_msg>Update docs<commit_after>//! The enum `Either`.

use std::io::{self, Write, Read, BufRead};
use std::convert::{AsRef, AsMut};
use std::ops::Deref;
use std::ops::DerefMut;

pub use Either::{Left, Right};

/// `Either` represents an alternative holding one value out of
/// either of the two possible values.
///
/// `Either` is a general purpose sum type of two parts. For representing
/// success or error, use the regular `Result<T, E>` instead.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Either<L, R> {
    /// A value of type `L`.
    Left(L),
    /// A value of type `R`.
    Right(R),
}

macro_rules! either {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref $inner) => $result,
            Either::Right(ref $inner) => $result,
        }
    )
}

macro_rules! either_mut {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref mut $inner) => $result,
            Either::Right(ref mut $inner) => $result,
        }
    )
}

impl<L, R> Either<L, R> {
    pub fn is_left(&self) -> bool {
        match *self {
            Left(_) => true,
            Right(_) => false,
        }
    }

    pub fn is_right(&self) -> bool {
        !self.is_left()
    }

    pub fn left(self) -> Option<L> {
        match self {
            Left(l) => Some(l),
            Right(_) => None,
        }
    }

    pub fn right(self) -> Option<R> {
        match self {
            Left(_) => None,
            Right(r) => Some(r),
        }
    }

    pub fn as_ref(&self) -> Either<&L, &R> {
        match *self {
            Left(ref inner) => Left(inner),
            Right(ref inner) => Right(inner),
        }
    }

    pub fn as_mut(&mut self) -> Either<&mut L, &mut R> {
        match *self {
            Left(ref mut inner) => Left(inner),
            Right(ref mut inner) => Right(inner),
        }
    }

    pub fn flip(self) -> Either<R, L> {
        match self {
            Left(l) => Right(l),
            Right(r) => Left(r),
        }
    }
}

/// Convert from `Result` to `Either` with `Ok => Right` and `Err => Left`.
impl<L, R> From<Result<R, L>> for Either<L, R> {
    fn from(r: Result<R, L>) -> Self {
        match r {
            Err(e) => Left(e),
            Ok(o) => Right(o),
        }
    }
}

/// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`.
impl<L, R> Into<Result<R, L>> for Either<L, R> {
    fn into(self) -> Result<R, L> {
        match self {
            Left(l) => Err(l),
            Right(r) => Ok(r),
        }
    }
}

/// `Either<L, R>` is an iterator if both `L` and `R` are iterators.
impl<L, R> Iterator for Either<L, R>
    where L: Iterator, R: Iterator<Item=L::Item>
{
    type Item = L::Item;

    fn next(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        either!(*self, inner => inner.size_hint())
    }
}

impl<L, R> DoubleEndedIterator for Either<L, R>
    where L: DoubleEndedIterator, R: DoubleEndedIterator<Item=L::Item>
{
    fn next_back(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next_back())
    }
}

impl<L, R> ExactSizeIterator for Either<L, R>
    where L: ExactSizeIterator, R: ExactSizeIterator<Item=L::Item>
{
}

/// `Either<L, R>` implements `Read` if both `L` and `R` do.
impl<L, R> Read for Either<L, R>
    where L: Read, R: Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read(buf))
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read_to_end(buf))
    }
}

impl<L, R> BufRead for Either<L, R>
    where L: BufRead, R: BufRead
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        either_mut!(*self, inner => inner.fill_buf())
    }

    fn consume(&mut self, amt: usize) {
        either_mut!(*self, inner => inner.consume(amt))
    }
}

/// `Either<L, R>` implements `Write` if both `L` and `R` do.
impl<L, R> Write for Either<L, R>
    where L: Write, R: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        either_mut!(*self, inner => inner.flush())
    }
}

impl<L, R, Target> AsRef<Target> for Either<L, R>
    where L: AsRef<Target>, R: AsRef<Target>
{
    fn as_ref(&self) -> &Target {
        either!(*self, inner => inner.as_ref())
    }
}

impl<L, R, Target> AsMut<Target> for Either<L, R>
    where L: AsMut<Target>, R: AsMut<Target>
{
    fn as_mut(&mut self) -> &mut Target {
        either_mut!(*self, inner => inner.as_mut())
    }
}

impl<L, R> Deref for Either<L, R>
    where L: Deref, R: Deref<Target=L::Target>
{
    type Target = L::Target;

    fn deref(&self) -> &Self::Target {
        either!(*self, inner => &*inner)
    }
}

impl<L, R> DerefMut for Either<L, R>
    where L: DerefMut, R: DerefMut<Target=L::Target>
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        either_mut!(*self, inner => &mut *inner)
    }
}

#[test]
fn basic() {
    let mut e = Left(2);
    let r = Right(2);
    assert_eq!(e, Left(2));
    e = r;
    assert_eq!(e, Right(2));
    assert_eq!(e.left(), None);
    assert_eq!(e.right(), Some(2));
    assert_eq!(e.as_ref().right(), Some(&2));
    assert_eq!(e.as_mut().right(), Some(&mut 2));
}

#[test]
fn deref() {
    fn is_str(_: &str) {}
    let value: Either<String, &str> = Left(String::from("test"));
    is_str(&*value);
}

#[test]
fn iter() {
    let x = 3;
    let mut iter = match x {
        1...3 => Left(0..10),
        _ => Right(17..),
    };

    assert_eq!(iter.next(), Some(0));
    assert_eq!(iter.count(), 9);
}

#[test]
fn read_write() {
    use std::io;

    let use_stdio = false;
    let mockdata = [0xff; 256];

    let mut reader = if use_stdio {
        Left(io::stdin())
    } else {
        Right(&mockdata[..])
    };

    let mut buf = [0u8; 16];
    assert_eq!(reader.read(&mut buf).unwrap(), buf.len());
    assert_eq!(&buf, &mockdata[..buf.len()]);

    let mut mockbuf = [0u8; 256];
    let mut writer = if use_stdio {
        Left(io::stdout())
    } else {
        Right(&mut mockbuf[..])
    };

    let buf = [1u8; 16];
    assert_eq!(writer.write(&buf).unwrap(), buf.len());
}
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(plugin))]
#![cfg_attr(test, plugin(quickcheck_macros))]

extern crate num;

#[cfg(test)] extern crate quickcheck;

use num::{Float, NumCast, Zero, cast};
use std::f64::consts::PI;
use std::fmt::{Display, Formatter, Error};
use std::ops::{Add, Div, Mul, Neg, Sub};

/// An angle.
///
/// Might be a value in degrees or in radians.
#[derive(Copy, Clone, Debug)]
pub enum Angle<T=f64> {
    Radians(T),
    Degrees(T)
}

impl<T: Copy + NumCast> Angle<T> {
    /// Yield the value encoded in radians.
    pub fn in_radians(&self) -> T {
        match *self {
            Radians(v) => v,
            Degrees(v) => cast(cast::<T, f64>(v).unwrap() / 180.0 * PI).unwrap()
        }
    }

    /// Yield the value encoded in degrees.
    pub fn in_degrees(&self) -> T {
        match *self {
            Radians(v) => cast(cast::<T, f64>(v).unwrap() / PI * 180.0).unwrap(),
            Degrees(v) => v
        }
    }
}

impl<T: Float + NumCast> Angle<T> {
    /// Create a new angle by normalizing the value into the range of
    /// [0, 2π) rad.
    pub fn normalized(&self) -> Angle<T> {
        let (v, upper) = match *self {
            Radians(v) => (v, cast(2.0 * PI).unwrap()),
            Degrees(v) => (v, cast(360.0).unwrap())
        };

        let normalized = if v < upper && v >= Zero::zero() {
            v
        } else {
            let v = v % upper;

            if v >= Zero::zero() {
                v
            } else {
                v + upper
            }
        };

        match *self {
            Radians(_) => Radians(normalized),
            Degrees(_) => Degrees(normalized)
        }
    }

    /// Compute the sine of the angle.
    pub fn sin(&self) -> T {
        self.in_radians().sin()
    }

    /// Compute the cosine of the angle.
    pub fn cos(&self) -> T {
        self.in_radians().cos()
    }

    /// Compute the tangent of the angle.
    pub fn tan(&self) -> T {
        self.in_radians().tan()
    }

    /// Simultaneously compute the sine and cosine of the number, `x`.
    /// Return `(sin(x), cos(x))`.
    pub fn sin_cos(&self) -> (T, T) {
        self.in_radians().sin_cos()
    }

    /*
    /// Computes the approximate mean of a set of angles by averaging the
    /// Cartesian coordinates of the angles on the unit circle.
    pub fn mean(angles: &[Angle<T>]) -> Angle<T> {
        let mut x: T = Zero::zero();
        let mut y: T = Zero::zero();

        for angle in angles.iter() {
            let radian = angle.as_radian();
            x = x + radian.cos();
            y = y + radian.sin();
        }

        let n = cast(angles.len()).unwrap();
        let a = (y/n).atan2(x/n);

        Radian(a).normalize()
    }

    /// Computes the minimal unsigned distance between two normalized angles.
    pub fn distance(&self, other: Angle<T>) -> Angle<T> {
        // FIXME: Once associated types are implemented fix this nightmares of casts #17841
        let pi: T = cast(f64::consts::PI).unwrap();
        let pi2: T = pi * cast(2.0).unwrap();
        let d = (self.as_radian() - other.as_radian()).abs();
        Radian(pi - ((d % (pi2)) - pi).abs())
    }*/
}

impl<T: Float> Angle<T> {
    /// Compute the arcsine of a number. Return value is in the range of
    /// [-π/2, π/2] rad or `None` if the number is outside the range [-1, 1].
    pub fn asin(value: T) -> Option<Angle<T>> {
        let value = value.asin();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arccosine of a number. Return value is in the range of
    /// [0, π] rad or `None` if the number is outside the range [-1, 1].
    pub fn acos(value: T) -> Option<Angle<T>> {
        let value = value.acos();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arctangent of a number. Return value is in the range of
    /// [-π/2, π/2] rad.
    pub fn atan(value: T) -> Angle<T> {
        Radians(value.atan())
    }

    // Computes the four quadrant arctangent of `y` and `x`.
    pub fn atan2(y: T, x: T) -> Angle<T> {
        Radians(y.atan2(x))
    }
}

/*
impl<T: Zero> Zero for Angle<T> {
    fn zero() -> Angle<T> {
        Radian(T::zero())
    }

    fn is_zero(&self) -> bool {
        match *self {
            Radian(v) => v == T::zero(),
            Degrees(v) => v == T::zero()
        }
    }
}*/

impl<T: PartialEq + Copy + NumCast> PartialEq for Angle<T> {
    fn eq(&self, other: &Angle<T>) -> bool {
        if let (Degrees(a), Degrees(b)) = (*self, *other) {
            a == b
        } else {
            self.in_radians() == other.in_radians()
        }
    }
}

macro_rules! math_additive(
    ($bound:ident, $func:ident) => (
        impl<T: $bound + Float + NumCast> $bound for Angle<T> {
            type Output = Angle<T>;
            fn $func(self, rhs: Angle<T>) -> Self::Output {
                if let (Degrees(a), Degrees(b)) = (self, rhs) {
                    Degrees(a.$func(b))
                } else {
                    Radians(self.in_radians().$func(rhs.in_radians()))
                }
            }
        }
    );
);

math_additive!(Add, add);
math_additive!(Sub, sub);

macro_rules! math_multiplicative(
    ($bound:ident, $func:ident, $($t:ident),*) => (
        impl<T: $bound> $bound<T> for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: T) -> Self::Output {
                match self {
                    Radians(v) => Radians(v.$func(rhs)),
                    Degrees(v) => Degrees(v.$func(rhs))
                }
            }
        }

        $(
            impl $bound<Angle<$t>> for $t {
                type Output = Angle<$t>;
                fn $func(self, rhs: Angle<$t>) -> Self::Output {
                    match rhs {
                        Radians(v) => Radians(self.$func(v)),
                        Degrees(v) => Degrees(self.$func(v))
                    }
                }
            }
        )*
    );
);

math_multiplicative!(Mul, mul, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);
math_multiplicative!(Div, div, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);

impl<T: Neg> Neg for Angle<T> {
    type Output = Angle<T::Output>;
    fn neg(self) -> Self::Output {
        match self {
            Radians(v) => Radians(-v),
            Degrees(v) => Degrees(-v)
        }
    }
}

impl<T: Display> Display for Angle<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Radians(ref v) => write!(f, "{}rad", v),
            Degrees(ref v) => write!(f, "{}°", v)
        }
    }
}

unsafe impl<T: Send> Send for Angle<T> {  }

/*
impl<T: Encodable + Float + NumCast> Encodable for Angle<T> {
    fn encode<S: Encoder>(&self,  s: &mut S) -> Result<(), S::Error> {
        self.as_radian().encode(s)
    }
}

impl<T: Decodable + Float + NumCast> Decodable for Angle<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let t = try!(T::decode(d));
        Ok(Angle::Radian(t))
    }
}
*/

// re-exports
pub use Angle::{Radians, Degrees};

#[cfg(test)]
mod tests {
    use num::{Float, cast};
    use quickcheck::{Arbitrary, Gen};
    use std::f64::consts::PI;
    use super::{Angle, Radians, Degrees};

    #[quickcheck]
    fn test_angle_conversions(angle: Angle<f64>) -> bool {
        are_close(angle.in_radians(), Degrees(angle.in_degrees()).in_radians())
    }

    #[quickcheck]
    fn test_angle_math_multiplicative(a: Angle<f64>, x: f64) -> bool {
        match a {
            Radians(v) => (a * x).in_radians() == v * x &&
                          (a / x).in_radians() == v / x,
            Degrees(v) => (a * x).in_degrees() == v * x &&
                          (a / x).in_degrees() == v / x
        }
    }

    #[quickcheck]
    fn test_angle_math_additive(a: Angle, b: Angle) -> bool {
        if let (Radians(x), Radians(y)) = (a, b) {
            (a + b).in_radians() == x + y &&
            (a - b).in_radians() == x - y
        } else if let (Degrees(x), Degrees(y)) = (a, b) {
            (a + b).in_degrees() == x + y &&
            (a - b).in_degrees() == x - y
        } else {
            (a + b).in_radians() == a.in_radians() + b.in_radians()
        }
    }

    #[quickcheck]
    fn test_angle_normalization(angle: Angle) -> bool {
        let v = angle.normalized();
        let rad = v.in_radians();
        let deg = v.in_degrees();

        0.0 <= rad && rad < 2.0 * PI &&
        0.0 <= deg && deg < 360.0 &&
        are_close(rad.cos(), angle.cos())
    }

    fn are_close<T: Float>(a: T, b: T) -> bool {
        (a - b).abs() < cast(1.0e-10).unwrap()
    }

    impl<T: Arbitrary> Arbitrary for Angle<T> {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let v = Arbitrary::arbitrary(g);
            if bool::arbitrary(g) {
                Radians(v)
            } else {
                Degrees(v)
            }
        }
    }
}
<commit_msg>Implement Zero trait for Angle<commit_after>#![cfg_attr(test, feature(plugin))]
#![cfg_attr(test, plugin(quickcheck_macros))]

extern crate num;

#[cfg(test)] extern crate quickcheck;

use num::{Float, Num, NumCast, Zero, cast};
use std::f64::consts::PI;
use std::fmt::{Display, Formatter, Error};
use std::ops::{Add, Div, Mul, Neg, Sub};

/// An angle.
///
/// Might be a value in degrees or in radians.
#[derive(Copy, Clone, Debug)]
pub enum Angle<T=f64> {
    Radians(T),
    Degrees(T)
}

impl<T: NumCast> Angle<T> {
    /// Yield the value encoded in radians.
    pub fn in_radians(self) -> T {
        match self {
            Radians(v) => v,
            Degrees(v) => cast(cast::<T, f64>(v).unwrap() / 180.0 * PI).unwrap()
        }
    }

    /// Yield the value encoded in degrees.
    pub fn in_degrees(self) -> T {
        match self {
            Radians(v) => cast(cast::<T, f64>(v).unwrap() / PI * 180.0).unwrap(),
            Degrees(v) => v
        }
    }
}

impl<T: Copy + Num + NumCast + PartialOrd> Angle<T> {
    /// Create a new angle by normalizing the value into the range of
    /// [0, 2π) rad.
    pub fn normalized(self) -> Angle<T> {
        let (v, upper) = match self {
            Radians(v) => (v, cast(2.0 * PI).unwrap()),
            Degrees(v) => (v, cast(360.0).unwrap())
        };

        let normalized = if v < upper && v >= Zero::zero() {
            v
        } else {
            let v = v % upper;

            if v >= Zero::zero() {
                v
            } else {
                v + upper
            }
        };

        match self {
            Radians(_) => Radians(normalized),
            Degrees(_) => Degrees(normalized)
        }
    }
}

impl<T: Float + NumCast> Angle<T> {
    /// Compute the sine of the angle.
    pub fn sin(self) -> T {
        self.in_radians().sin()
    }

    /// Compute the cosine of the angle.
    pub fn cos(self) -> T {
        self.in_radians().cos()
    }

    /// Compute the tangent of the angle.
    pub fn tan(self) -> T {
        self.in_radians().tan()
    }

    /// Simultaneously compute the sine and cosine of the number, `x`.
    /// Return `(sin(x), cos(x))`.
    pub fn sin_cos(self) -> (T, T) {
        self.in_radians().sin_cos()
    }

    /*
    /// Computes the approximate mean of a set of angles by averaging the
    /// Cartesian coordinates of the angles on the unit circle.
    pub fn mean(angles: &[Angle<T>]) -> Angle<T> {
        let mut x: T = Zero::zero();
        let mut y: T = Zero::zero();

        for angle in angles.iter() {
            let radian = angle.as_radian();
            x = x + radian.cos();
            y = y + radian.sin();
        }

        let n = cast(angles.len()).unwrap();
        let a = (y/n).atan2(x/n);

        Radian(a).normalize()
    }

    /// Computes the minimal unsigned distance between two normalized angles.
    pub fn distance(&self, other: Angle<T>) -> Angle<T> {
        // FIXME: Once associated types are implemented fix this nightmares of casts #17841
        let pi: T = cast(f64::consts::PI).unwrap();
        let pi2: T = pi * cast(2.0).unwrap();
        let d = (self.as_radian() - other.as_radian()).abs();
        Radian(pi - ((d % (pi2)) - pi).abs())
    }*/
}

impl<T: Float> Angle<T> {
    /// Compute the arcsine of a number. Return value is in the range of
    /// [-π/2, π/2] rad or `None` if the number is outside the range [-1, 1].
    pub fn asin(value: T) -> Option<Angle<T>> {
        let value = value.asin();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arccosine of a number. Return value is in the range of
    /// [0, π] rad or `None` if the number is outside the range [-1, 1].
    pub fn acos(value: T) -> Option<Angle<T>> {
        let value = value.acos();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arctangent of a number. Return value is in the range of
    /// [-π/2, π/2] rad.
    pub fn atan(value: T) -> Angle<T> {
        Radians(value.atan())
    }

    // Computes the four quadrant arctangent of `y` and `x`.
    pub fn atan2(y: T, x: T) -> Angle<T> {
        Radians(y.atan2(x))
    }
}

impl<T: Zero + Copy + NumCast> Zero for Angle<T> {
    fn zero() -> Self {
        Radians(T::zero())
    }

    fn is_zero(&self) -> bool {
        match self {
            &Radians(ref v) => v.is_zero(),
            &Degrees(ref v) => v.is_zero()
        }
    }
}

impl<T: PartialEq + Copy + NumCast> PartialEq for Angle<T> {
    fn eq(&self, other: &Angle<T>) -> bool {
        if let (Degrees(a), Degrees(b)) = (*self, *other) {
            a == b
        } else {
            self.in_radians() == other.in_radians()
        }
    }
}

macro_rules! math_additive(
    ($bound:ident, $func:ident) => (
        impl<T: $bound + Copy + NumCast> $bound for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: Angle<T>) -> Self::Output {
                if let (Degrees(a), Degrees(b)) = (self, rhs) {
                    Degrees(a.$func(b))
                } else {
                    Radians(self.in_radians().$func(rhs.in_radians()))
                }
            }
        }
    );
);

math_additive!(Add, add);
math_additive!(Sub, sub);

macro_rules! math_multiplicative(
    ($bound:ident, $func:ident, $($t:ident),*) => (
        impl<T: $bound> $bound<T> for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: T) -> Self::Output {
                match self {
                    Radians(v) => Radians(v.$func(rhs)),
                    Degrees(v) => Degrees(v.$func(rhs))
                }
            }
        }

        $(
            impl $bound<Angle<$t>> for $t {
                type Output = Angle<$t>;
                fn $func(self, rhs: Angle<$t>) -> Self::Output {
                    match rhs {
                        Radians(v) => Radians(self.$func(v)),
                        Degrees(v) => Degrees(self.$func(v))
                    }
                }
            }
        )*
    );
);

math_multiplicative!(Mul, mul, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);
math_multiplicative!(Div, div, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);

impl<T: Neg> Neg for Angle<T> {
    type Output = Angle<T::Output>;
    fn neg(self) -> Self::Output {
        match self {
            Radians(v) => Radians(-v),
            Degrees(v) => Degrees(-v)
        }
    }
}

impl<T: Display> Display for Angle<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Radians(ref v) => write!(f, "{}rad", v),
            Degrees(ref v) => write!(f, "{}°", v)
        }
    }
}

unsafe impl<T: Send> Send for Angle<T> {  }

/*
impl<T: Encodable + Float + NumCast> Encodable for Angle<T> {
    fn encode<S: Encoder>(&self,  s: &mut S) -> Result<(), S::Error> {
        self.as_radian().encode(s)
    }
}

impl<T: Decodable + Float + NumCast> Decodable for Angle<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let t = try!(T::decode(d));
        Ok(Angle::Radian(t))
    }
}
*/

// re-exports
pub use Angle::{Radians, Degrees};

#[cfg(test)]
mod tests {
    use num::{Float, cast};
    use quickcheck::{Arbitrary, Gen};
    use std::f64::consts::PI;
    use super::{Angle, Radians, Degrees};

    #[quickcheck]
    fn test_angle_conversions(angle: Angle<f64>) -> bool {
        are_close(angle.in_radians(), Degrees(angle.in_degrees()).in_radians())
    }

    #[quickcheck]
    fn test_angle_math_multiplicative(a: Angle<f64>, x: f64) -> bool {
        match a {
            Radians(v) => (a * x).in_radians() == v * x &&
                          (a / x).in_radians() == v / x,
            Degrees(v) => (a * x).in_degrees() == v * x &&
                          (a / x).in_degrees() == v / x
        }
    }

    #[quickcheck]
    fn test_angle_math_additive(a: Angle, b: Angle) -> bool {
        if let (Radians(x), Radians(y)) = (a, b) {
            (a + b).in_radians() == x + y &&
            (a - b).in_radians() == x - y
        } else if let (Degrees(x), Degrees(y)) = (a, b) {
            (a + b).in_degrees() == x + y &&
            (a - b).in_degrees() == x - y
        } else {
            (a + b).in_radians() == a.in_radians() + b.in_radians()
        }
    }

    #[quickcheck]
    fn test_angle_normalization(angle: Angle) -> bool {
        let v = angle.normalized();
        let rad = v.in_radians();
        let deg = v.in_degrees();

        0.0 <= rad && rad < 2.0 * PI &&
        0.0 <= deg && deg < 360.0 &&
        are_close(rad.cos(), angle.cos())
    }

    fn are_close<T: Float>(a: T, b: T) -> bool {
        (a - b).abs() < cast(1.0e-10).unwrap()
    }

    impl<T: Arbitrary> Arbitrary for Angle<T> {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let v = Arbitrary::arbitrary(g);
            if bool::arbitrary(g) {
                Radians(v)
            } else {
                Degrees(v)
            }
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "byteorder"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/byteorder")]

#![feature(io)]
#![allow(dead_code, unused_variables)]

use std::old_io::IoResult;

// A trivial logging macro. No reason to pull in `log`, which has become
// difficult to use in tests.
macro_rules! lg {
    ($($arg:tt)*) => ({
        let _ = ::std::old_io::stderr().write_str(&*format!($($arg)*));
        let _ = ::std::old_io::stderr().write_str("\n");
    });
}

pub trait ByteOrder {
    fn read_u16(bs: &[u8]) -> u16;
    fn read_u32(bs: &[u8]) -> u32;
    fn read_u64(bs: &[u8]) -> u64;
    fn write_u16(bs: &mut [u8], n: u16);
    fn write_u32(bs: &mut [u8], n: u32);
    fn write_u64(bs: &mut [u8], n: u64);

    fn read_i16(bs: &[u8]) -> i16 {
        <Self as ByteOrder>::read_u16(bs) as i16
    }

    fn write_i16(bs: &mut [u8], n: i16) {
        <Self as ByteOrder>::write_u16(bs, n as u16)
    }

    fn read_i32(bs: &[u8]) -> i32 {
        <Self as ByteOrder>::read_u32(bs) as i32
    }

    fn write_i32(bs: &mut [u8], n: i32) {
        <Self as ByteOrder>::write_u32(bs, n as u32)
    }

    fn read_i64(bs: &[u8]) -> i64 {
        <Self as ByteOrder>::read_u64(bs) as i64
    }

    fn write_i64(bs: &mut [u8], n: i64) {
        <Self as ByteOrder>::write_u64(bs, n as u64)
    }
}

pub trait ReaderBytesExt: Reader + Sized {
    fn read_u8(&mut self) -> IoResult<u8> {
        let mut bs = &mut [0; 1];
        try!(read_full(self, bs));
        Ok(bs[0])
    }

    fn read_i8(&mut self) -> IoResult<i8> {
        let mut bs = &mut [0; 1];
        try!(read_full(self, bs));
        Ok(bs[0] as i8)
    }

    fn read_u16<T: ByteOrder>(&mut self) -> IoResult<u16> {
        let mut bs = &mut [0; 2];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_u16(bs))
    }

    fn read_i16<T: ByteOrder>(&mut self) -> IoResult<i16> {
        let mut bs = &mut [0; 2];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_i16(bs))
    }

    fn read_u32<T: ByteOrder>(&mut self) -> IoResult<u32> {
        let mut bs = &mut [0; 4];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_u32(bs))
    }

    fn read_i32<T: ByteOrder>(&mut self) -> IoResult<i32> {
        let mut bs = &mut [0; 4];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_i32(bs))
    }

    fn read_u64<T: ByteOrder>(&mut self) -> IoResult<u64> {
        let mut bs = &mut [0; 8];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_u64(bs))
    }

    fn read_i64<T: ByteOrder>(&mut self) -> IoResult<i64> {
        let mut bs = &mut [0; 8];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_i64(bs))
    }
}

impl<R: Reader> ReaderBytesExt for R {}

fn read_full<R: Reader>(rdr: &mut R, buf: &mut [u8]) -> IoResult<()> {
    let mut n = 0us;
    while n < buf.len() {
        n += try!(rdr.read(&mut buf[n..]));
    }
    Ok(())
}

pub trait WriterBytesExt: Writer + Sized {
    fn write_u8(&mut self, n: u8) -> IoResult<()> {
        self.write_all(&[n])
    }

    fn write_i8(&mut self, n: i8) -> IoResult<()> {
        self.write_all(&[n as u8])
    }

    fn write_u16<T: ByteOrder>(&mut self, n: u16) -> IoResult<()> {
        let mut bs = &mut [0; 2];
        <T as ByteOrder>::write_u16(bs, n);
        self.write_all(bs)
    }

    fn write_i16<T: ByteOrder>(&mut self, n: i16) -> IoResult<()> {
        let mut bs = &mut [0; 2];
        <T as ByteOrder>::write_i16(bs, n);
        self.write_all(bs)
    }

    fn write_u32<T: ByteOrder>(&mut self, n: u32) -> IoResult<()> {
        let mut bs = &mut [0; 4];
        <T as ByteOrder>::write_u32(bs, n);
        self.write_all(bs)
    }

    fn write_i32<T: ByteOrder>(&mut self, n: i32) -> IoResult<()> {
        let mut bs = &mut [0; 4];
        <T as ByteOrder>::write_i32(bs, n);
        self.write_all(bs)
    }

    fn write_u64<T: ByteOrder>(&mut self, n: u64) -> IoResult<()> {
        let mut bs = &mut [0; 8];
        <T as ByteOrder>::write_u64(bs, n);
        self.write_all(bs)
    }

    fn write_i64<T: ByteOrder>(&mut self, n: i64) -> IoResult<()> {
        let mut bs = &mut [0; 8];
        <T as ByteOrder>::write_i64(bs, n);
        self.write_all(bs)
    }
}

impl<W: Writer> WriterBytesExt for W {}

#[allow(missing_copy_implementations)] pub struct BigEndian;
#[allow(missing_copy_implementations)] pub struct LittleEndian;

impl ByteOrder for BigEndian {
    fn read_u16(bs: &[u8]) -> u16 {
        ((bs[0] as u16) << 8) | (bs[1] as u16)
    }

    fn read_u32(bs: &[u8]) -> u32 {
        (bs[0] as u32) << 24
        | (bs[1] as u32) << 16
        | (bs[2] as u32) << 8
        | (bs[3] as u32)
    }

    fn read_u64(bs: &[u8]) -> u64 {
        (bs[0] as u64) << 56
        | (bs[1] as u64) << 48
        | (bs[2] as u64) << 40
        | (bs[3] as u64) << 32
        | (bs[4] as u64) << 24
        | (bs[5] as u64) << 16
        | (bs[6] as u64) << 8
        | (bs[7] as u64)
    }

    fn write_u16(bs: &mut [u8], n: u16) {
        bs[0] = (n >> 8) as u8;
        bs[1] = n as u8;
    }

    fn write_u32(bs: &mut [u8], n: u32) {
        bs[0] = (n >> 24) as u8;
        bs[1] = (n >> 16) as u8;
        bs[2] = (n >> 8) as u8;
        bs[3] = n as u8;
    }

    fn write_u64(bs: &mut [u8], n: u64) {
        bs[0] = (n >> 56) as u8;
        bs[1] = (n >> 48) as u8;
        bs[2] = (n >> 40) as u8;
        bs[3] = (n >> 32) as u8;
        bs[4] = (n >> 24) as u8;
        bs[5] = (n >> 16) as u8;
        bs[6] = (n >> 8) as u8;
        bs[7] = n as u8;
    }
}

impl ByteOrder for LittleEndian {
    fn read_u16(bs: &[u8]) -> u16 {
        bs[0] as u16 | (bs[1] as u16) << 8
    }

    fn read_u32(bs: &[u8]) -> u32 {
        (bs[0] as u32)
        | (bs[1] as u32) << 8
        | (bs[2] as u32) << 16
        | (bs[3] as u32) << 24
    }

    fn read_u64(bs: &[u8]) -> u64 {
        (bs[0] as u64)
        | (bs[1] as u64) << 8
        | (bs[2] as u64) << 16
        | (bs[3] as u64) << 24
        | (bs[4] as u64) << 32
        | (bs[5] as u64) << 40
        | (bs[6] as u64) << 48
        | (bs[7] as u64) << 56
    }

    fn write_u16(bs: &mut [u8], n: u16) {
        bs[0] = n as u8;
        bs[1] = (n >> 8) as u8;
    }

    fn write_u32(bs: &mut [u8], n: u32) {
        bs[0] = n as u8;
        bs[1] = (n >> 8) as u8;
        bs[2] = (n >> 16) as u8;
        bs[3] = (n >> 24) as u8;
    }

    fn write_u64(bs: &mut [u8], n: u64) {
        bs[0] = n as u8;
        bs[1] = (n >> 8) as u8;
        bs[2] = (n >> 16) as u8;
        bs[3] = (n >> 24) as u8;
        bs[4] = (n >> 32) as u8;
        bs[5] = (n >> 40) as u8;
        bs[6] = (n >> 48) as u8;
        bs[7] = (n >> 56) as u8;
    }
}

#[cfg(test)]
mod test {
    extern crate quickcheck;

    macro_rules! qc_byte_order {
        ($name:ident, $ty_int:ty, $read:ident, $write:ident) => (
            mod $name {
                use test::quickcheck::quickcheck;
                use {BigEndian, ByteOrder, LittleEndian};

                #[test]
                fn big_endian() {
                    fn prop(n: $ty_int) -> bool {
                        let bs = &mut [0; 8];
                        <BigEndian as ByteOrder>::$write(bs, n);
                        n == <BigEndian as ByteOrder>::$read(bs)
                    }
                    quickcheck(prop as fn($ty_int) -> bool);
                }

                #[test]
                fn little_endian() {
                    fn prop(n: $ty_int) -> bool {
                        let bs = &mut [0; 8];
                        <LittleEndian as ByteOrder>::$write(bs, n);
                        n == <LittleEndian as ByteOrder>::$read(bs)
                    }
                    quickcheck(prop as fn($ty_int) -> bool);
                }
            }
        );
    }

    qc_byte_order!(prop_u16, u16, read_u16, write_u16);
    qc_byte_order!(prop_i16, i16, read_i16, write_i16);
    qc_byte_order!(prop_u32, u32, read_u32, write_u32);
    qc_byte_order!(prop_i32, i32, read_i32, write_i32);
    qc_byte_order!(prop_u64, u64, read_u64, write_u64);
    qc_byte_order!(prop_i64, i64, read_i64, write_i64);
}
<commit_msg>Make order markers uninstantiable<commit_after>#![crate_name = "byteorder"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/byteorder")]

#![feature(io)]
#![allow(dead_code, unused_variables)]

use std::old_io::IoResult;

// A trivial logging macro. No reason to pull in `log`, which has become
// difficult to use in tests.
macro_rules! lg {
    ($($arg:tt)*) => ({
        let _ = ::std::old_io::stderr().write_str(&*format!($($arg)*));
        let _ = ::std::old_io::stderr().write_str("\n");
    });
}

pub trait ByteOrder {
    fn read_u16(bs: &[u8]) -> u16;
    fn read_u32(bs: &[u8]) -> u32;
    fn read_u64(bs: &[u8]) -> u64;
    fn write_u16(bs: &mut [u8], n: u16);
    fn write_u32(bs: &mut [u8], n: u32);
    fn write_u64(bs: &mut [u8], n: u64);

    fn read_i16(bs: &[u8]) -> i16 {
        <Self as ByteOrder>::read_u16(bs) as i16
    }

    fn write_i16(bs: &mut [u8], n: i16) {
        <Self as ByteOrder>::write_u16(bs, n as u16)
    }

    fn read_i32(bs: &[u8]) -> i32 {
        <Self as ByteOrder>::read_u32(bs) as i32
    }

    fn write_i32(bs: &mut [u8], n: i32) {
        <Self as ByteOrder>::write_u32(bs, n as u32)
    }

    fn read_i64(bs: &[u8]) -> i64 {
        <Self as ByteOrder>::read_u64(bs) as i64
    }

    fn write_i64(bs: &mut [u8], n: i64) {
        <Self as ByteOrder>::write_u64(bs, n as u64)
    }
}

pub trait ReaderBytesExt: Reader + Sized {
    fn read_u8(&mut self) -> IoResult<u8> {
        let mut bs = &mut [0; 1];
        try!(read_full(self, bs));
        Ok(bs[0])
    }

    fn read_i8(&mut self) -> IoResult<i8> {
        let mut bs = &mut [0; 1];
        try!(read_full(self, bs));
        Ok(bs[0] as i8)
    }

    fn read_u16<T: ByteOrder>(&mut self) -> IoResult<u16> {
        let mut bs = &mut [0; 2];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_u16(bs))
    }

    fn read_i16<T: ByteOrder>(&mut self) -> IoResult<i16> {
        let mut bs = &mut [0; 2];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_i16(bs))
    }

    fn read_u32<T: ByteOrder>(&mut self) -> IoResult<u32> {
        let mut bs = &mut [0; 4];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_u32(bs))
    }

    fn read_i32<T: ByteOrder>(&mut self) -> IoResult<i32> {
        let mut bs = &mut [0; 4];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_i32(bs))
    }

    fn read_u64<T: ByteOrder>(&mut self) -> IoResult<u64> {
        let mut bs = &mut [0; 8];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_u64(bs))
    }

    fn read_i64<T: ByteOrder>(&mut self) -> IoResult<i64> {
        let mut bs = &mut [0; 8];
        try!(read_full(self, bs));
        Ok(<T as ByteOrder>::read_i64(bs))
    }
}

impl<R: Reader> ReaderBytesExt for R {}

fn read_full<R: Reader>(rdr: &mut R, buf: &mut [u8]) -> IoResult<()> {
    let mut n = 0us;
    while n < buf.len() {
        n += try!(rdr.read(&mut buf[n..]));
    }
    Ok(())
}

pub trait WriterBytesExt: Writer + Sized {
    fn write_u8(&mut self, n: u8) -> IoResult<()> {
        self.write_all(&[n])
    }

    fn write_i8(&mut self, n: i8) -> IoResult<()> {
        self.write_all(&[n as u8])
    }

    fn write_u16<T: ByteOrder>(&mut self, n: u16) -> IoResult<()> {
        let mut bs = &mut [0; 2];
        <T as ByteOrder>::write_u16(bs, n);
        self.write_all(bs)
    }

    fn write_i16<T: ByteOrder>(&mut self, n: i16) -> IoResult<()> {
        let mut bs = &mut [0; 2];
        <T as ByteOrder>::write_i16(bs, n);
        self.write_all(bs)
    }

    fn write_u32<T: ByteOrder>(&mut self, n: u32) -> IoResult<()> {
        let mut bs = &mut [0; 4];
        <T as ByteOrder>::write_u32(bs, n);
        self.write_all(bs)
    }

    fn write_i32<T: ByteOrder>(&mut self, n: i32) -> IoResult<()> {
        let mut bs = &mut [0; 4];
        <T as ByteOrder>::write_i32(bs, n);
        self.write_all(bs)
    }

    fn write_u64<T: ByteOrder>(&mut self, n: u64) -> IoResult<()> {
        let mut bs = &mut [0; 8];
        <T as ByteOrder>::write_u64(bs, n);
        self.write_all(bs)
    }

    fn write_i64<T: ByteOrder>(&mut self, n: i64) -> IoResult<()> {
        let mut bs = &mut [0; 8];
        <T as ByteOrder>::write_i64(bs, n);
        self.write_all(bs)
    }
}

impl<W: Writer> WriterBytesExt for W {}

#[allow(missing_copy_implementations)] pub enum BigEndian {}
#[allow(missing_copy_implementations)] pub enum LittleEndian {}

impl ByteOrder for BigEndian {
    fn read_u16(bs: &[u8]) -> u16 {
        ((bs[0] as u16) << 8) | (bs[1] as u16)
    }

    fn read_u32(bs: &[u8]) -> u32 {
        (bs[0] as u32) << 24
        | (bs[1] as u32) << 16
        | (bs[2] as u32) << 8
        | (bs[3] as u32)
    }

    fn read_u64(bs: &[u8]) -> u64 {
        (bs[0] as u64) << 56
        | (bs[1] as u64) << 48
        | (bs[2] as u64) << 40
        | (bs[3] as u64) << 32
        | (bs[4] as u64) << 24
        | (bs[5] as u64) << 16
        | (bs[6] as u64) << 8
        | (bs[7] as u64)
    }

    fn write_u16(bs: &mut [u8], n: u16) {
        bs[0] = (n >> 8) as u8;
        bs[1] = n as u8;
    }

    fn write_u32(bs: &mut [u8], n: u32) {
        bs[0] = (n >> 24) as u8;
        bs[1] = (n >> 16) as u8;
        bs[2] = (n >> 8) as u8;
        bs[3] = n as u8;
    }

    fn write_u64(bs: &mut [u8], n: u64) {
        bs[0] = (n >> 56) as u8;
        bs[1] = (n >> 48) as u8;
        bs[2] = (n >> 40) as u8;
        bs[3] = (n >> 32) as u8;
        bs[4] = (n >> 24) as u8;
        bs[5] = (n >> 16) as u8;
        bs[6] = (n >> 8) as u8;
        bs[7] = n as u8;
    }
}

impl ByteOrder for LittleEndian {
    fn read_u16(bs: &[u8]) -> u16 {
        bs[0] as u16 | (bs[1] as u16) << 8
    }

    fn read_u32(bs: &[u8]) -> u32 {
        (bs[0] as u32)
        | (bs[1] as u32) << 8
        | (bs[2] as u32) << 16
        | (bs[3] as u32) << 24
    }

    fn read_u64(bs: &[u8]) -> u64 {
        (bs[0] as u64)
        | (bs[1] as u64) << 8
        | (bs[2] as u64) << 16
        | (bs[3] as u64) << 24
        | (bs[4] as u64) << 32
        | (bs[5] as u64) << 40
        | (bs[6] as u64) << 48
        | (bs[7] as u64) << 56
    }

    fn write_u16(bs: &mut [u8], n: u16) {
        bs[0] = n as u8;
        bs[1] = (n >> 8) as u8;
    }

    fn write_u32(bs: &mut [u8], n: u32) {
        bs[0] = n as u8;
        bs[1] = (n >> 8) as u8;
        bs[2] = (n >> 16) as u8;
        bs[3] = (n >> 24) as u8;
    }

    fn write_u64(bs: &mut [u8], n: u64) {
        bs[0] = n as u8;
        bs[1] = (n >> 8) as u8;
        bs[2] = (n >> 16) as u8;
        bs[3] = (n >> 24) as u8;
        bs[4] = (n >> 32) as u8;
        bs[5] = (n >> 40) as u8;
        bs[6] = (n >> 48) as u8;
        bs[7] = (n >> 56) as u8;
    }
}

#[cfg(test)]
mod test {
    extern crate quickcheck;

    macro_rules! qc_byte_order {
        ($name:ident, $ty_int:ty, $read:ident, $write:ident) => (
            mod $name {
                use test::quickcheck::quickcheck;
                use {BigEndian, ByteOrder, LittleEndian};

                #[test]
                fn big_endian() {
                    fn prop(n: $ty_int) -> bool {
                        let bs = &mut [0; 8];
                        <BigEndian as ByteOrder>::$write(bs, n);
                        n == <BigEndian as ByteOrder>::$read(bs)
                    }
                    quickcheck(prop as fn($ty_int) -> bool);
                }

                #[test]
                fn little_endian() {
                    fn prop(n: $ty_int) -> bool {
                        let bs = &mut [0; 8];
                        <LittleEndian as ByteOrder>::$write(bs, n);
                        n == <LittleEndian as ByteOrder>::$read(bs)
                    }
                    quickcheck(prop as fn($ty_int) -> bool);
                }
            }
        );
    }

    qc_byte_order!(prop_u16, u16, read_u16, write_u16);
    qc_byte_order!(prop_i16, i16, read_i16, write_i16);
    qc_byte_order!(prop_u32, u32, read_u32, write_u32);
    qc_byte_order!(prop_i32, i32, read_i32, write_i32);
    qc_byte_order!(prop_u64, u64, read_u64, write_u64);
    qc_byte_order!(prop_i64, i64, read_i64, write_i64);
}
<|endoftext|>


<commit_before>extern crate capsize;

use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};

static FORMAT: &'static str = "[=>_]";

pub struct Bar<'a> {
    prefix: &'a str,
    total: usize,
    current: AtomicUsize,
    format: &'a str
}

impl<'a> Bar<'a> {
    pub fn new(total: usize, prefix: Option<&'a str>) -> Bar<'a> {
        Bar {
            prefix: prefix.unwrap_or(""),
            total: total,
            current: AtomicUsize::new(0),
            format: FORMAT
        }
    }

    pub fn incr(&self) -> usize {
        self.add(1)
    }

    pub fn add(&self, delta: usize) -> usize {
        self.current.fetch_add(delta, Ordering::Relaxed)
    }

    pub fn width(&self) -> usize {
        80
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        self.write(current)
    }

    pub fn finish_print(&self, msg: &str) {
        println!("{}",msg)
    }

    fn repeat(what: &str, n: usize) -> String {
        iter::repeat(what).take(n).collect::<String>()
    }

    fn write(&self, current: usize) {
        let width = self.width();
        let prefix_display = self.prefix;

        let formats = self.format.split("").collect::<Vec<&str>>();
        let bar_start = formats[1];
        let current_marker = formats[2];
        let current_n = formats[3];
        let empty = formats[4];
        let bar_end = formats[5];

        let mut bar_display = String::new();
        let counter_display = format!(
            "{} / {} ", current, self.total
        );
        let percent = current as f64 / (self.total as f64 / 100_f64);
        let percent_display = format!(
            " {:.*} %", 2, percent
        );
        let bar_width = format!(
            "{}{}{}{}{}", prefix_display, counter_display, percent_display, bar_start, bar_end
        ).chars().collect::<Vec<char>>().len();
        let size = width - bar_width;
        let cur_count = (
            (current as f64 / self.total as f64) * size as f64
        ).ceil() as usize;
        let empt_count = size - cur_count;
        bar_display.push_str(bar_start);
        bar_display.push_str(
            &Bar::repeat(current_marker, (cur_count - 1) as usize)
        );
        bar_display.push_str(current_n);
        bar_display.push_str(
            &Bar::repeat(empty, (empt_count) as usize)
        );
        bar_display.push_str(bar_end);
        print!("\r{}{}{}{}", prefix_display, counter_display, bar_display, percent_display)
    }
}

#[test]
fn it_works() {
}
<commit_msg>simplify<commit_after>extern crate capsize;

use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};

static FORMAT: &'static str = "[=>_]";

pub struct Bar {
    prefix: String,
    total: usize,
    current: AtomicUsize,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String,
    show_percent: bool,
    show_counter: bool,
    show_bar: bool
}

impl Bar {
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            prefix: String::new(),
            total: total,
            current: AtomicUsize::new(0),
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_empty: String::new(),
            bar_end: String::new(),
            show_percent: true,
            show_counter: true,
            show_bar: true
        };
        bar.format(FORMAT);
        bar
    }

    /// bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        self.current.fetch_add(delta, Ordering::Relaxed)
    }

    pub fn width(&self) -> usize {
        80
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        self.write(current)
    }

    pub fn finish_print(&self, msg: &str) {
        println!("{}",msg)
    }

    fn write(&self, current: usize) {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        let width = self.width();

        let mut prefix = String::new();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = format!(
                "{} / {} ", current, self.total
            );
        }

        // percent complete
        if self.show_percent {
            let percent = current as f64 / (self.total as f64 / 100_f64);
            suffix = suffix + &format!(
                " {:.*} %", 2, percent
            );
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }

        print!("\r{}", display)
    }
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};

/// An Optional value can contain Optional::Some<T> or Optional::Absent.
/// It is similar to an Option, but Optional::Absent means it will be
/// omitted when serialized.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }
}

pub struct Location {
    pub address: Optional<String>,
    pub lat: f64,
    pub lon: f64,
}

pub struct Spacefed {
    pub spacenet: bool,
    pub spacesaml: bool,
    pub spacephone: bool,
}

pub struct Icon {
    pub open: String,
    pub close: String,
}

pub struct State {
    pub open: Option<bool>,
    pub lastchange: Optional<u64>,
    pub trigger_person: Optional<String>,
    pub message: Optional<String>,
    pub icon: Optional<Icon>,
}

pub struct Event {
    pub name: String,
    pub _type: String,
    pub timestamp: u64,
    pub extra: Optional<String>,
}

pub struct Contact {
    pub irc: Optional<String>,
    pub twitter: Optional<String>,
    pub foursquare: Optional<String>,
    pub email: Optional<String>,
}

pub struct Feed {
    pub _type: Optional<String>,
    pub url: String,
}

pub struct Feeds {
    pub blog: Optional<Feed>,
    pub wiki: Optional<Feed>,
    pub calendar: Optional<Feed>,
    pub flickr: Optional<Feed>,
}

pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

pub struct PeopleNowPresentSensor {
    pub value: u32,
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

pub struct TemperatureSensor {
    pub value: f32,
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

pub struct Cache {
    pub schedule: String,
}

pub struct RadioShow {
    pub name: String,
    pub url: String,
    pub _type: String,
    pub start: String,
    pub end: String,
}

pub struct Status {

    // Hackerspace properties
    pub api: String,
    pub space: String,
    pub logo: String,
    pub url: String,
    pub location: Location,
    pub contact: Contact,

    // Hackerspace features / projects
    pub spacefed: Optional<Spacefed>,
    pub projects: Optional<Vec<String>>,
    pub cam: Optional<Vec<String>>,
    pub feeds: Optional<Feeds>,
    pub events: Optional<Vec<Event>>,
    pub radio_show: Optional<Vec<RadioShow>>,

    // SpaceAPI internal usage
    pub cache: Optional<Cache>,
    pub issue_report_channels: Vec<String>,

    // Mutable data
    pub state: State,
    pub sensors: Optional<Sensors>,

}

impl Status {

    /// Create a new Status object with only the minimum amount of fields
    pub fn new(space: String, logo: String, url: String, location: Location, contact: Contact, issue_report_channels: Vec<String>) -> Status {
        Status {
            api: "0.13".to_string(),
            space: space,
            logo: logo,
            url: url,
            location: location,
            contact: contact,

            spacefed: Optional::Absent,
            projects: Optional::Absent,
            cam: Optional::Absent,
            feeds: Optional::Absent,
            events: Optional::Absent,
            radio_show: Optional::Absent,

            cache: Optional::Absent,
            issue_report_channels: issue_report_channels,

            state: State {
                open: None,
                lastchange: Optional::Absent,
                trigger_person: Optional::Absent,
                message: Optional::Absent,
                icon: Optional::Absent,
            },
            sensors: Optional::Absent,
        }
    }

}

impl ToJson for Status {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        d.insert("api".to_string(), self.api.to_json());
        d.insert("space".to_string(), self.space.to_json());
        d.insert("logo".to_string(), self.logo.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("location".to_string(), self.location.to_json());
        d.insert("contact".to_string(), self.contact.to_json());

        match self.spacefed {
            Optional::Value(ref spacefed) => { d.insert("spacefed".to_string(), spacefed.to_json()); },
            Optional::Absent => (),
        };
        match self.projects {
            Optional::Value(ref projects) => { d.insert("projects".to_string(), projects.to_json()); },
            Optional::Absent => (),
        };
        match self.cam {
            Optional::Value(ref cam) => { d.insert("cam".to_string(), cam.to_json()); },
            Optional::Absent => (),
        };
        match self.feeds {
            Optional::Value(ref feeds) => { d.insert("feeds".to_string(), feeds.to_json()); },
            Optional::Absent => (),
        };
        match self.events {
            Optional::Value(ref events) => { d.insert("events".to_string(), events.to_json()); },
            Optional::Absent => (),
        };
        match self.radio_show {
            Optional::Value(ref radio_show) => { d.insert("radio_show".to_string(), radio_show.to_json()); },
            Optional::Absent => (),
        };

        match self.cache {
            Optional::Value(ref cache) => { d.insert("cache".to_string(), cache.to_json()); },
            Optional::Absent => (),
        };
        d.insert("issue_report_channels".to_string(), self.issue_report_channels.to_json());

        d.insert("state".to_string(), self.state.to_json());
        match self.sensors {
            Optional::Value(ref sensors) => { d.insert("sensors".to_string(), sensors.to_json()); },
            Optional::Absent => (),
        };

        Json::Object(d)
    }
}

impl ToJson for Location {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("lat".to_string(), self.lat.to_json());
        d.insert("lon".to_string(), self.lon.to_json());
        match self.address {
            Optional::Value(ref address) => {
                d.insert("address".to_string(), address.to_json());
            },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Spacefed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("spacenet".to_string(), self.spacenet.to_json());
        d.insert("spacesaml".to_string(), self.spacesaml.to_json());
        d.insert("spacephone".to_string(), self.spacephone.to_json());
        Json::Object(d)
    }
}

impl ToJson for Icon {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        d.insert("close".to_string(), self.close.to_json());
        Json::Object(d)
    }
}

impl ToJson for State {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        match self.lastchange {
            Optional::Value(ref lastchange) => { d.insert("lastchange".to_string(), lastchange.to_json()); },
            Optional::Absent => (),
        };
        match self.trigger_person {
            Optional::Value(ref trigger_person) => { d.insert("trigger_person".to_string(), trigger_person.to_json()); },
            Optional::Absent => (),
        };
        match self.message {
            Optional::Value(ref message) => { d.insert("message".to_string(), message.to_json()); },
            Optional::Absent => (),
        };
        match self.icon {
            Optional::Value(ref icon) => { d.insert("icon".to_string(), icon.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("timestamp".to_string(), self.timestamp.to_json());
        match self.extra {
            Optional::Value(ref extra) => { d.insert("extra".to_string(), extra.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Contact {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.irc {
            Optional::Value(ref irc) => { d.insert("irc".to_string(), irc.to_json()); },
            Optional::Absent => (),
        };
        match self.twitter {
            Optional::Value(ref twitter) => { d.insert("twitter".to_string(), twitter.to_json()); },
            Optional::Absent => (),
        };
        match self.foursquare {
            Optional::Value(ref foursquare) => { d.insert("foursquare".to_string(), foursquare.to_json()); },
            Optional::Absent => (),
        };
        match self.email {
            Optional::Value(ref email) => { d.insert("email".to_string(), email.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Feed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string(), self.url.to_json());
        match self._type {
            Optional::Value(ref _type) => { d.insert("type".to_string(), _type.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Feeds {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.blog {
            Optional::Value(ref blog) => { d.insert("blog".to_string(), blog.to_json()); },
            Optional::Absent => (),
        };
        match self.wiki {
            Optional::Value(ref wiki) => { d.insert("wiki".to_string(), wiki.to_json()); },
            Optional::Absent => (),
        };
        match self.calendar {
            Optional::Value(ref calendar) => { d.insert("calendar".to_string(), calendar.to_json()); },
            Optional::Absent => (),
        };
        match self.flickr {
            Optional::Value(ref flickr) => { d.insert("flickr".to_string(), flickr.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.people_now_present {
            Optional::Value(ref people_now_present) => { d.insert("people_now_present".to_string(), people_now_present.to_json()); },
            Optional::Absent => (),
        };
        match self.temperature {
            Optional::Value(ref temperature) => { d.insert("temperature".to_string(), temperature.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        match self.location {
            Optional::Value(ref location) => { d.insert("location".to_string(), location.to_json()); },
            Optional::Absent => (),
        };
        match self.name {
            Optional::Value(ref name) => { d.insert("name".to_string(), name.to_json()); },
            Optional::Absent => (),
        };
        match self.names {
            Optional::Value(ref names) => { d.insert("names".to_string(), names.to_json()); },
            Optional::Absent => (),
        };
        match self.description {
            Optional::Value(ref description) => { d.insert("description".to_string(), description.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        match self.name {
            Optional::Value(ref name) => { d.insert("name".to_string(), name.to_json()); },
            Optional::Absent => (),
        };
        match self.description {
            Optional::Value(ref description) => { d.insert("description".to_string(), description.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Cache {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("schedule".to_string(), self.schedule.to_json());
        Json::Object(d)
    }
}

impl ToJson for RadioShow {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("start".to_string(), self.start.to_json());
        d.insert("end".to_string(), self.end.to_json());
        Json::Object(d)
    }
}
<commit_msg>spaceapi: Add Optional.as_ref()/as_mut()<commit_after>extern crate rustc_serialize;

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};

/// An Optional value can contain Optional::Some<T> or Optional::Absent.
/// It is similar to an Option, but Optional::Absent means it will be
/// omitted when serialized.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }
}

pub struct Location {
    pub address: Optional<String>,
    pub lat: f64,
    pub lon: f64,
}

pub struct Spacefed {
    pub spacenet: bool,
    pub spacesaml: bool,
    pub spacephone: bool,
}

pub struct Icon {
    pub open: String,
    pub close: String,
}

pub struct State {
    pub open: Option<bool>,
    pub lastchange: Optional<u64>,
    pub trigger_person: Optional<String>,
    pub message: Optional<String>,
    pub icon: Optional<Icon>,
}

pub struct Event {
    pub name: String,
    pub _type: String,
    pub timestamp: u64,
    pub extra: Optional<String>,
}

pub struct Contact {
    pub irc: Optional<String>,
    pub twitter: Optional<String>,
    pub foursquare: Optional<String>,
    pub email: Optional<String>,
}

pub struct Feed {
    pub _type: Optional<String>,
    pub url: String,
}

pub struct Feeds {
    pub blog: Optional<Feed>,
    pub wiki: Optional<Feed>,
    pub calendar: Optional<Feed>,
    pub flickr: Optional<Feed>,
}

pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

pub struct PeopleNowPresentSensor {
    pub value: u32,
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

pub struct TemperatureSensor {
    pub value: f32,
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

pub struct Cache {
    pub schedule: String,
}

pub struct RadioShow {
    pub name: String,
    pub url: String,
    pub _type: String,
    pub start: String,
    pub end: String,
}

pub struct Status {

    // Hackerspace properties
    pub api: String,
    pub space: String,
    pub logo: String,
    pub url: String,
    pub location: Location,
    pub contact: Contact,

    // Hackerspace features / projects
    pub spacefed: Optional<Spacefed>,
    pub projects: Optional<Vec<String>>,
    pub cam: Optional<Vec<String>>,
    pub feeds: Optional<Feeds>,
    pub events: Optional<Vec<Event>>,
    pub radio_show: Optional<Vec<RadioShow>>,

    // SpaceAPI internal usage
    pub cache: Optional<Cache>,
    pub issue_report_channels: Vec<String>,

    // Mutable data
    pub state: State,
    pub sensors: Optional<Sensors>,

}

impl Status {

    /// Create a new Status object with only the minimum amount of fields
    pub fn new(space: String, logo: String, url: String, location: Location, contact: Contact, issue_report_channels: Vec<String>) -> Status {
        Status {
            api: "0.13".to_string(),
            space: space,
            logo: logo,
            url: url,
            location: location,
            contact: contact,

            spacefed: Optional::Absent,
            projects: Optional::Absent,
            cam: Optional::Absent,
            feeds: Optional::Absent,
            events: Optional::Absent,
            radio_show: Optional::Absent,

            cache: Optional::Absent,
            issue_report_channels: issue_report_channels,

            state: State {
                open: None,
                lastchange: Optional::Absent,
                trigger_person: Optional::Absent,
                message: Optional::Absent,
                icon: Optional::Absent,
            },
            sensors: Optional::Absent,
        }
    }

}

impl ToJson for Status {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        d.insert("api".to_string(), self.api.to_json());
        d.insert("space".to_string(), self.space.to_json());
        d.insert("logo".to_string(), self.logo.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("location".to_string(), self.location.to_json());
        d.insert("contact".to_string(), self.contact.to_json());

        match self.spacefed {
            Optional::Value(ref spacefed) => { d.insert("spacefed".to_string(), spacefed.to_json()); },
            Optional::Absent => (),
        };
        match self.projects {
            Optional::Value(ref projects) => { d.insert("projects".to_string(), projects.to_json()); },
            Optional::Absent => (),
        };
        match self.cam {
            Optional::Value(ref cam) => { d.insert("cam".to_string(), cam.to_json()); },
            Optional::Absent => (),
        };
        match self.feeds {
            Optional::Value(ref feeds) => { d.insert("feeds".to_string(), feeds.to_json()); },
            Optional::Absent => (),
        };
        match self.events {
            Optional::Value(ref events) => { d.insert("events".to_string(), events.to_json()); },
            Optional::Absent => (),
        };
        match self.radio_show {
            Optional::Value(ref radio_show) => { d.insert("radio_show".to_string(), radio_show.to_json()); },
            Optional::Absent => (),
        };

        match self.cache {
            Optional::Value(ref cache) => { d.insert("cache".to_string(), cache.to_json()); },
            Optional::Absent => (),
        };
        d.insert("issue_report_channels".to_string(), self.issue_report_channels.to_json());

        d.insert("state".to_string(), self.state.to_json());
        match self.sensors {
            Optional::Value(ref sensors) => { d.insert("sensors".to_string(), sensors.to_json()); },
            Optional::Absent => (),
        };

        Json::Object(d)
    }
}

impl ToJson for Location {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("lat".to_string(), self.lat.to_json());
        d.insert("lon".to_string(), self.lon.to_json());
        match self.address {
            Optional::Value(ref address) => {
                d.insert("address".to_string(), address.to_json());
            },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Spacefed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("spacenet".to_string(), self.spacenet.to_json());
        d.insert("spacesaml".to_string(), self.spacesaml.to_json());
        d.insert("spacephone".to_string(), self.spacephone.to_json());
        Json::Object(d)
    }
}

impl ToJson for Icon {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        d.insert("close".to_string(), self.close.to_json());
        Json::Object(d)
    }
}

impl ToJson for State {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        match self.lastchange {
            Optional::Value(ref lastchange) => { d.insert("lastchange".to_string(), lastchange.to_json()); },
            Optional::Absent => (),
        };
        match self.trigger_person {
            Optional::Value(ref trigger_person) => { d.insert("trigger_person".to_string(), trigger_person.to_json()); },
            Optional::Absent => (),
        };
        match self.message {
            Optional::Value(ref message) => { d.insert("message".to_string(), message.to_json()); },
            Optional::Absent => (),
        };
        match self.icon {
            Optional::Value(ref icon) => { d.insert("icon".to_string(), icon.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("timestamp".to_string(), self.timestamp.to_json());
        match self.extra {
            Optional::Value(ref extra) => { d.insert("extra".to_string(), extra.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Contact {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.irc {
            Optional::Value(ref irc) => { d.insert("irc".to_string(), irc.to_json()); },
            Optional::Absent => (),
        };
        match self.twitter {
            Optional::Value(ref twitter) => { d.insert("twitter".to_string(), twitter.to_json()); },
            Optional::Absent => (),
        };
        match self.foursquare {
            Optional::Value(ref foursquare) => { d.insert("foursquare".to_string(), foursquare.to_json()); },
            Optional::Absent => (),
        };
        match self.email {
            Optional::Value(ref email) => { d.insert("email".to_string(), email.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Feed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string(), self.url.to_json());
        match self._type {
            Optional::Value(ref _type) => { d.insert("type".to_string(), _type.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Feeds {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.blog {
            Optional::Value(ref blog) => { d.insert("blog".to_string(), blog.to_json()); },
            Optional::Absent => (),
        };
        match self.wiki {
            Optional::Value(ref wiki) => { d.insert("wiki".to_string(), wiki.to_json()); },
            Optional::Absent => (),
        };
        match self.calendar {
            Optional::Value(ref calendar) => { d.insert("calendar".to_string(), calendar.to_json()); },
            Optional::Absent => (),
        };
        match self.flickr {
            Optional::Value(ref flickr) => { d.insert("flickr".to_string(), flickr.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.people_now_present {
            Optional::Value(ref people_now_present) => { d.insert("people_now_present".to_string(), people_now_present.to_json()); },
            Optional::Absent => (),
        };
        match self.temperature {
            Optional::Value(ref temperature) => { d.insert("temperature".to_string(), temperature.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        match self.location {
            Optional::Value(ref location) => { d.insert("location".to_string(), location.to_json()); },
            Optional::Absent => (),
        };
        match self.name {
            Optional::Value(ref name) => { d.insert("name".to_string(), name.to_json()); },
            Optional::Absent => (),
        };
        match self.names {
            Optional::Value(ref names) => { d.insert("names".to_string(), names.to_json()); },
            Optional::Absent => (),
        };
        match self.description {
            Optional::Value(ref description) => { d.insert("description".to_string(), description.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        match self.name {
            Optional::Value(ref name) => { d.insert("name".to_string(), name.to_json()); },
            Optional::Absent => (),
        };
        match self.description {
            Optional::Value(ref description) => { d.insert("description".to_string(), description.to_json()); },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Cache {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("schedule".to_string(), self.schedule.to_json());
        Json::Object(d)
    }
}

impl ToJson for RadioShow {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("start".to_string(), self.start.to_json());
        d.insert("end".to_string(), self.end.to_json());
        Json::Object(d)
    }
}
<|endoftext|>