<commit_before>use std::rc::Rc;
use std::cell::Ref;
use std::sync::mpsc;
use std::fmt;
use types::{MaybeOwned, Storage, SharedSignal, SharedImpl};
use stream::Stream;

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `sample_with` methods. They update lazily when someone reads them.
#[derive(Debug)]
pub struct Signal<T>(SigValue<T>);

enum SigValue<T>
{
    /// A signal with constant value.
    ///
    /// We store the value in a Rc to provide Clone support without a `T: Clone` bound.
    Constant(Rc<T>),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Rc<Fn() -> T>),
    /// A signal that contains shared data.
    ///
    /// This is produced by stream methods that create a signal.
    Shared(Rc<SharedSignal<T>>),
    /// A signal that contains a signal, and allows sampling the inner signal directly.
    ///
    /// This is produced by `Signal::switch`
    Nested(Rc<Fn() -> Signal<T>>),
}

impl<T> Signal<T>
{
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub fn constant<V: Into<Rc<T>>>(val: V) -> Self
    {
        Signal(Constant(val.into()))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
        where F: Fn() -> T + 'static
    {
        Signal(Dynamic(Rc::new(f)))
    }

    /// Creates a new shared signal.
    pub(crate) fn shared<S>(storage: S) -> Self
        where S: SharedSignal<T> + 'static
    {
        Signal(Shared(Rc::new(storage)))
    }

    /// Checks if the signal has changed since the last time it was sampled.
    pub fn has_changed(&self) -> bool
    {
        match self.0 {
            Constant(_) => false,
            Dynamic(_) | Nested(_) => true,
            Shared(ref s) => { s.update(); s.has_changed() },
        }
    }

    /// Sample by reference.
    ///
    /// This is meant to be the most efficient way when cloning is undesirable,
    /// but it requires a callback to prevent outliving internal borrows.
    pub fn sample_with<F, R>(&self, cb: F) -> R
        where F: FnOnce(MaybeOwned<T>) -> R
    {
        match self.0
        {
            Constant(ref val) => cb(MaybeOwned::Borrowed(val)),
            Dynamic(ref f) => cb(MaybeOwned::Owned(f())),
            Shared(ref s) => { s.update(); cb(MaybeOwned::Borrowed(&s.sample())) },
            Nested(ref f) => f().sample_with(cb),
        }
    }
}

impl<T: Clone> Signal<T>
{
    /// Sample by value.
    ///
    /// This will clone the content of the signal.
    pub fn sample(&self) -> T
    {
        match self.0
        {
            Constant(ref val) => (**val).clone(),
            Dynamic(ref f) => f(),
            Shared(ref s) => { s.update(); s.sample().clone() },
            Nested(ref f) => f().sample(),
        }
    }
}

impl<T: 'static> Signal<T>
{
    /// Maps a signal with the provided function.
    ///
    /// The closure is called only when the parent signal changes.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
        where F: Fn(MaybeOwned<T>) -> R + 'static,
        R: 'static
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => {
                Signal::constant(f(MaybeOwned::Borrowed(val)))
            }
            // shared signal: apply f only when the parent signal has changed
            Shared(ref sig) => Signal::shared(SharedImpl{
                storage: Storage::inherit(sig.storage()),
                source: sig.clone(),
                f,
            }),
            // dynamic/nested signal: apply f unconditionally
            Dynamic(_) | Nested(_) => {
                let this = self.clone();
                Signal::from_fn(move || this.sample_with(&f))
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
        where F: Fn(MaybeOwned<T>, MaybeOwned<S>) -> R + 'static,
        S: 'static, R: 'static
    {
        let this = self.clone();
        trigger.map(move |b| this.sample_with(|a| f(a, b)))
    }

    /// Creates a signal from a shared value.
    pub(crate) fn from_storage<P: 'static>(storage: Rc<SharedImpl<T, P, ()>>) -> Self
    {
        Signal(Shared(storage))
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
        where F: Fn(T, V) -> T + 'static,
        V: 'static
    {
        Signal::shared(SharedImpl{
            storage: Storage::new(initial),
            source: rx,
            f,
        })
    }
}

impl<T: 'static> Signal<Signal<T>>
{
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T>
    {
        match self.0
        {
            // constant signal: just extract the inner signal
            Constant(ref sig) => (**sig).clone(),
            // dynamic signal: re-label as nested
            Dynamic(ref f) => Signal(Nested(f.clone())),
            // shared signal: sample to extract the inner signal
            Shared(ref sig_) => {
                let sig = sig_.clone();
                Signal(Nested(Rc::new(move || { sig.update(); sig.sample().clone() })))
            }
            // nested signal: remove one layer
            Nested(ref f_) => {
                let f = f_.clone();
                Signal(Nested(Rc::new(move || f().sample())))
            }
        }
    }
}

impl<T: Default> Default for Signal<T>
{
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self
    {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T>
{
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self
    {
        Signal::constant(val)
    }
}

impl<T> From<Rc<T>> for Signal<T>
{
    /// Creates a constant signal from T (avoids re-wrapping the Rc).
    #[inline]
    fn from(val: Rc<T>) -> Self
    {
        Signal(Constant(val))
    }
}

// the derive impl adds a `T: Clone` we don't want
impl<T> Clone for Signal<T>
{
    /// Creates a copy of this signal that references the same value.
    fn clone(&self) -> Self
    {
        Signal(match self.0
        {
            Constant(ref val) => Constant(val.clone()),
            Dynamic(ref rf) => Dynamic(rf.clone()),
            Shared(ref rs) => Shared(rs.clone()),
            Nested(ref rf) => Nested(rf.clone()),
        })
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
            Shared(ref rs) => write!(f, "Shared(SignalShared@{:p})", rs),
            Nested(ref rf) => write!(f, "Nested(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display> fmt::Display for Signal<T>
{
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        self.sample_with(|val| fmt::Display::fmt(&*val, f))
    }
}

// A signal that contains only storage.

impl<T, S> SharedImpl<T, S, ()>
{
    pub fn new(initial: T, source: S) -> Self
    {
        SharedImpl{
            storage: Storage::new(initial),
            source,
            f: (),
        }
    }
}

impl<T, S> SharedSignal<T> for SharedImpl<T, S, ()>
{
    fn update(&self) {}

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.storage.borrow()
    }
}

// A signal that maps a parent shared signal.

impl<T, P, F> SharedSignal<T> for SharedImpl<T, Rc<SharedSignal<P>>, F>
    where F: Fn(MaybeOwned<P>) -> T + 'static
{
    fn update(&self)
    {
        self.source.update()
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        if self.has_changed()
        {
            let res = (self.f)(MaybeOwned::Borrowed(&self.source.sample()));
            self.storage.set_local(res);
        }
        self.storage.borrow()
    }
}

// A signal that folds a channel.

impl<T, S, F> SharedSignal<T> for SharedImpl<T, mpsc::Receiver<S>, F>
    where F: Fn(T, S) -> T + 'static,
{
    fn update(&self)
    {
        if let Ok(first) = self.source.try_recv()
        {
            let acc = (self.f)(self.storage.take(), first);
            let new = self.source.try_iter().fold(acc, &self.f);
            self.storage.set(new);
        }
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.update();
        self.storage.inc_local();
        self.storage.borrow()
    }
}

#[cfg(test)]
mod tests
{
    use super::*;
    use std::rc::Rc;
    use std::cell::Cell;
    use std::time::Instant;

    #[test]
    fn signal_basic()
    {
        let signal = Signal::constant(42);
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
        signal.sample_with(|val| assert_eq!(*val, 42));
    }

    #[test]
    fn signal_shared()
    {
        let st = Rc::new(SharedImpl::new(1, ()));
        let signal = Signal::from_storage(st.clone());
        let double = signal.map(|a| *a * 2);

        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        st.set(42);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
    }

    #[test]
    fn signal_dynamic()
    {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);
        signal.sample_with(|val| assert_eq!(*val, t));

        let n = Rc::new(Cell::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || cloned.get());
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        n.set(13);
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }
}
<commit_msg>added sample_with!(s1, s2, ...; f) macro<commit_after>use std::rc::Rc;
use std::cell::Ref;
use std::sync::mpsc;
use std::fmt;
use types::{MaybeOwned, Storage, SharedSignal, SharedImpl};
use stream::Stream;

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `sample_with` methods. They update lazily when someone reads them.
#[derive(Debug)]
pub struct Signal<T>(SigValue<T>);

enum SigValue<T>
{
    /// A signal with constant value.
    ///
    /// We store the value in a Rc to provide Clone support without a `T: Clone` bound.
    Constant(Rc<T>),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Rc<Fn() -> T>),
    /// A signal that contains shared data.
    ///
    /// This is produced by stream methods that create a signal.
    Shared(Rc<SharedSignal<T>>),
    /// A signal that contains a signal, and allows sampling the inner signal directly.
    ///
    /// This is produced by `Signal::switch`
    Nested(Rc<Fn() -> Signal<T>>),
}

impl<T> Signal<T>
{
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub fn constant<V: Into<Rc<T>>>(val: V) -> Self
    {
        Signal(Constant(val.into()))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
        where F: Fn() -> T + 'static
    {
        Signal(Dynamic(Rc::new(f)))
    }

    /// Creates a new shared signal.
    pub(crate) fn shared<S>(storage: S) -> Self
        where S: SharedSignal<T> + 'static
    {
        Signal(Shared(Rc::new(storage)))
    }

    /// Checks if the signal has changed since the last time it was sampled.
    pub fn has_changed(&self) -> bool
    {
        match self.0 {
            Constant(_) => false,
            Dynamic(_) | Nested(_) => true,
            Shared(ref s) => { s.update(); s.has_changed() },
        }
    }

    /// Sample by reference.
    ///
    /// This is meant to be the most efficient way when cloning is undesirable,
    /// but it requires a callback to prevent outliving internal borrows.
    pub fn sample_with<F, R>(&self, cb: F) -> R
        where F: FnOnce(MaybeOwned<T>) -> R
    {
        match self.0
        {
            Constant(ref val) => cb(MaybeOwned::Borrowed(val)),
            Dynamic(ref f) => cb(MaybeOwned::Owned(f())),
            Shared(ref s) => { s.update(); cb(MaybeOwned::Borrowed(&s.sample())) },
            Nested(ref f) => f().sample_with(cb),
        }
    }
}

impl<T: Clone> Signal<T>
{
    /// Sample by value.
    ///
    /// This will clone the content of the signal.
    pub fn sample(&self) -> T
    {
        match self.0
        {
            Constant(ref val) => (**val).clone(),
            Dynamic(ref f) => f(),
            Shared(ref s) => { s.update(); s.sample().clone() },
            Nested(ref f) => f().sample(),
        }
    }
}

impl<T: 'static> Signal<T>
{
    /// Maps a signal with the provided function.
    ///
    /// The closure is called only when the parent signal changes.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
        where F: Fn(MaybeOwned<T>) -> R + 'static,
        R: 'static
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => {
                Signal::constant(f(MaybeOwned::Borrowed(val)))
            }
            // shared signal: apply f only when the parent signal has changed
            Shared(ref sig) => Signal::shared(SharedImpl{
                storage: Storage::inherit(sig.storage()),
                source: sig.clone(),
                f,
            }),
            // dynamic/nested signal: apply f unconditionally
            Dynamic(_) | Nested(_) => {
                let this = self.clone();
                Signal::from_fn(move || this.sample_with(&f))
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
        where F: Fn(MaybeOwned<T>, MaybeOwned<S>) -> R + 'static,
        S: 'static, R: 'static
    {
        let this = self.clone();
        trigger.map(move |b| this.sample_with(|a| f(a, b)))
    }

    /// Creates a signal from a shared value.
    pub(crate) fn from_storage<P: 'static>(storage: Rc<SharedImpl<T, P, ()>>) -> Self
    {
        Signal(Shared(storage))
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
        where F: Fn(T, V) -> T + 'static,
        V: 'static
    {
        Signal::shared(SharedImpl{
            storage: Storage::new(initial),
            source: rx,
            f,
        })
    }
}

impl<T: 'static> Signal<Signal<T>>
{
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T>
    {
        match self.0
        {
            // constant signal: just extract the inner signal
            Constant(ref sig) => (**sig).clone(),
            // dynamic signal: re-label as nested
            Dynamic(ref f) => Signal(Nested(f.clone())),
            // shared signal: sample to extract the inner signal
            Shared(ref sig_) => {
                let sig = sig_.clone();
                Signal(Nested(Rc::new(move || { sig.update(); sig.sample().clone() })))
            }
            // nested signal: remove one layer
            Nested(ref f_) => {
                let f = f_.clone();
                Signal(Nested(Rc::new(move || f().sample())))
            }
        }
    }
}

impl<T: Default> Default for Signal<T>
{
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self
    {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T>
{
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self
    {
        Signal::constant(val)
    }
}

impl<T> From<Rc<T>> for Signal<T>
{
    /// Creates a constant signal from T (avoids re-wrapping the Rc).
    #[inline]
    fn from(val: Rc<T>) -> Self
    {
        Signal(Constant(val))
    }
}

// the derive impl adds a `T: Clone` we don't want
impl<T> Clone for Signal<T>
{
    /// Creates a copy of this signal that references the same value.
    fn clone(&self) -> Self
    {
        Signal(match self.0
        {
            Constant(ref val) => Constant(val.clone()),
            Dynamic(ref rf) => Dynamic(rf.clone()),
            Shared(ref rs) => Shared(rs.clone()),
            Nested(ref rf) => Nested(rf.clone()),
        })
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
            Shared(ref rs) => write!(f, "Shared(SignalShared@{:p})", rs),
            Nested(ref rf) => write!(f, "Nested(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display> fmt::Display for Signal<T>
{
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        self.sample_with(|val| fmt::Display::fmt(&*val, f))
    }
}

// A signal that contains only storage.

impl<T, S> SharedImpl<T, S, ()>
{
    pub fn new(initial: T, source: S) -> Self
    {
        SharedImpl{
            storage: Storage::new(initial),
            source,
            f: (),
        }
    }
}

impl<T, S> SharedSignal<T> for SharedImpl<T, S, ()>
{
    fn update(&self) {}

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.storage.borrow()
    }
}

// A signal that maps a parent shared signal.

impl<T, P, F> SharedSignal<T> for SharedImpl<T, Rc<SharedSignal<P>>, F>
    where F: Fn(MaybeOwned<P>) -> T + 'static
{
    fn update(&self)
    {
        self.source.update()
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        if self.has_changed()
        {
            let res = (self.f)(MaybeOwned::Borrowed(&self.source.sample()));
            self.storage.set_local(res);
        }
        self.storage.borrow()
    }
}

// A signal that folds a channel.

impl<T, S, F> SharedSignal<T> for SharedImpl<T, mpsc::Receiver<S>, F>
    where F: Fn(T, S) -> T + 'static,
{
    fn update(&self)
    {
        if let Ok(first) = self.source.try_recv()
        {
            let acc = (self.f)(self.storage.take(), first);
            let new = self.source.try_iter().fold(acc, &self.f);
            self.storage.set(new);
        }
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.update();
        self.storage.inc_local();
        self.storage.borrow()
    }
}

/// Helper for using `Signal::sample_with` with multiple signals.
///
/// Called as: `sample_with!(s1, s2, ...; f)`
/// where `s1: Signal<S1>, s2: Signal<S2>, ...` are N input signals,
/// and `f(MaybeOwned<S1>, MaybeOwned<S2>, ...) -> R` is a function that takes N arguments.
#[macro_export]
macro_rules! sample_with
{
    (@impl $f:expr ; ; $($var:ident)+) => ( $f($($var),+) );

    (@impl $f:expr ; $sig:expr, $($tail:expr,)* ; $($var:ident)*) => (
        $crate::Signal::sample_with(&$sig, |a| sample_with!(@impl $f; $($tail,)*; $($var)* a))
    );

    ($($sig:expr),+ ; $f:expr) => ( sample_with!(@impl $f; $($sig,)+;) );
}

#[cfg(test)]
mod tests
{
    use super::*;
    use std::rc::Rc;
    use std::cell::Cell;
    use std::time::Instant;

    #[test]
    fn signal_basic()
    {
        let signal = Signal::constant(42);
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
        signal.sample_with(|val| assert_eq!(*val, 42));
    }

    #[test]
    fn signal_shared()
    {
        let st = Rc::new(SharedImpl::new(1, ()));
        let signal = Signal::from_storage(st.clone());
        let double = signal.map(|a| *a * 2);

        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        st.set(42);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
    }

    #[test]
    fn signal_dynamic()
    {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);
        signal.sample_with(|val| assert_eq!(*val, t));

        let n = Rc::new(Cell::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || cloned.get());
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        n.set(13);
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn sample_with_macro()
    {
        let s1 = Signal::constant(30);
        let s2 = Signal::from_fn(|| 12);
        let s3 = Signal::from_storage(Rc::new(SharedImpl::new(100, ())));

        let res = sample_with!(s1, s2, s3;
            |x: MaybeOwned<i32>, y: MaybeOwned<i32>, z: MaybeOwned<i32>| *x + *y + *z);

        assert_eq!(res, 142);
    }
}
<|endoftext|>


<commit_before>use error::*;
use path;
use std::collections::HashMap;
use std::fmt::Debug;
use std::str::FromStr;
use value::{Value, ValueKind};

/// Describes a generic _source_ of configuration properties.
pub trait Source: Debug {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync>;

    /// Collect all configuration properties available from this source and return
    /// a HashMap.
    fn collect(&self) -> Result<HashMap<String, Value>>;

    fn collect_to(&self, cache: &mut Value) -> Result<()> {
        let props = match self.collect() {
            Ok(props) => props,
            Err(error) => {
                return Err(error);
            }
        };

        for (key, val) in &props {
            match path::Expression::from_str(key) {
                // Set using the path
                Ok(expr) => expr.set(cache, val.clone()),

                // Set diretly anyway
                _ => path::Expression::Identifier(key.clone()).set(cache, val.clone()),
            }
        }

        Ok(())
    }
}

impl Clone for Box<dyn Source + Send + Sync> {
    fn clone(&self) -> Box<dyn Source + Send + Sync> {
        self.clone_into_box()
    }
}

impl Source for Vec<Box<dyn Source + Send + Sync>> {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}

impl<T> Source for Vec<T>
where
    T: Source + Sync + Send,
    T: Clone,
    T: 'static,
{
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}
<commit_msg>Simplify implementation<commit_after>use error::*;
use path;
use std::collections::HashMap;
use std::fmt::Debug;
use std::str::FromStr;
use value::{Value, ValueKind};

/// Describes a generic _source_ of configuration properties.
pub trait Source: Debug {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync>;

    /// Collect all configuration properties available from this source and return
    /// a HashMap.
    fn collect(&self) -> Result<HashMap<String, Value>>;

    fn collect_to(&self, cache: &mut Value) -> Result<()> {
        self.collect()?
            .iter()
            .for_each(|(key, val)| match path::Expression::from_str(key) {
                // Set using the path
                Ok(expr) => expr.set(cache, val.clone()),

                // Set diretly anyway
                _ => path::Expression::Identifier(key.clone()).set(cache, val.clone()),
            });

        Ok(())
    }
}

impl Clone for Box<dyn Source + Send + Sync> {
    fn clone(&self) -> Box<dyn Source + Send + Sync> {
        self.clone_into_box()
    }
}

impl Source for Vec<Box<dyn Source + Send + Sync>> {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}

impl<T> Source for Vec<T>
where
    T: Source + Sync + Send,
    T: Clone,
    T: 'static,
{
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}
<|endoftext|>


<commit_before>use super::structure::{Program,Condition,Command,Expression,Sensor};

pub trait Source {
	fn source(&self) -> String;
}

impl Source for Program {
	fn source(&self) -> String {
		match *self {
			Program::If(ref condition, ref left, ref right) => format!("iff!({},{},{})", condition.source(), left.source(), right.source()),
			Program::Command(ref command)                   => command.source(),
		}
	}
}

impl Source for Condition {
	fn source(&self) -> String {
		match *self {
			Condition::True                              => format!("T!()"),
			Condition::False                             => format!("F!()"),
			Condition::Not(ref condition)                => format!("not!({})", (*condition).source()),
			Condition::Or(ref left, ref right)           => format!("or!({},{})", (*left).source(), (*right).source()),
			Condition::And(ref left, ref right)          => format!("and!({},{})", (*left).source(), (*right).source()),

			Condition::Less(ref left, ref right)         => format!("less!({},{})", (*left).source(), (*right).source()),
			Condition::LessEqual(ref left, ref right)    => format!("less_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Equal(ref left, ref right)        => format!("equal!({},{})", (*left).source(), (*right).source()),
			Condition::GreaterEqual(ref left, ref right) => format!("greater_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Greater(ref left, ref right)      => format!("greater!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Expression {
	fn source(&self) -> String {
		match *self {
			Expression::Constant(value)               => format!("constant!({:.*})", 4, value),
			Expression::Sensor(ref sensor)            => sensor.source(),
			Expression::Plus(ref left, ref right)     => format!("plus!({},{})", (*left).source(), (*right).source()),
			Expression::Minus(ref left, ref right)    => format!("minus!({},{})", (*left).source(), (*right).source()),
			Expression::Multiply(ref left, ref right) => format!("multiply!({},{})", (*left).source(), (*right).source()),
			Expression::Divide(ref left, ref right)   => format!("divide!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Sensor {
	fn source(&self) -> String {
		match *self {
			Sensor::X  => format!("x!()"),
			Sensor::Y  => format!("u!()"),
			Sensor::Vx => format!("vx!()"),
			Sensor::Vy => format!("vy!()"),
			Sensor::O  => format!("o!()"),
			Sensor::W  => format!("w!()"),
		}
	}
}

impl Source for Command {
	fn source(&self) -> String {
		match *self {
			Command::Skip  => format!("skip!()"),
			Command::Left  => format!("left!()"),
			Command::Right => format!("right!()"),
			Command::Up    => format!("up!()"),
		}
	}
}

#[test]
fn should_correctly_source_programs() {
	assert_eq!("iff!(T!(),skip!(),left!())",
		Program::If(Condition::True, Box::new(Program::Command(Command::Skip)), Box::new(Program::Command(Command::Left))).source());
	assert_eq!("skip!()", Program::Command(Command::Skip).source());
}

#[test]
fn should_correctly_source_conditions() {
	assert_eq!("T!()", Condition::True.source());
	assert_eq!("F!()", Condition::False.source());
	assert_eq!("not!(T!())", Condition::Not(Box::new(Condition::True)).source());
	assert_eq!("or!(T!(),F!())", Condition::Or(Box::new(Condition::True), Box::new(Condition::False)).source());
	assert_eq!("and!(F!(),T!())", Condition::And(Box::new(Condition::False), Box::new(Condition::True)).source());
	assert_eq!("less!(constant!(1.0000),constant!(2.0000))",
		Condition::Less(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("less_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::LessEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("equal!(constant!(1.0000),constant!(2.0000))",
		Condition::Equal(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::GreaterEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater!(constant!(1.0000),constant!(2.0000))",
		Condition::Greater(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_expressions() {
	assert_eq!("constant!(1.0000)", Expression::Constant(1.0).source());
	assert_eq!("vx!()", Expression::Sensor(Sensor::Vx).source());
	assert_eq!("plus!(constant!(1.0000),vy!())",
		Expression::Plus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Sensor(Sensor::Vy))).source());
	assert_eq!("minus!(constant!(1.0000),constant!(2.0000))",
		Expression::Minus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("multiply!(constant!(1.0000),constant!(2.0000))",
		Expression::Multiply(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("divide!(constant!(1.0000),constant!(2.0000))",
		Expression::Divide(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_sensors() {
	assert_eq!("x!()",  Sensor::X.source());
	assert_eq!("u!()",  Sensor::Y.source());
	assert_eq!("vx!()", Sensor::Vx.source());
	assert_eq!("vy!()", Sensor::Vy.source());
	assert_eq!("o!()",  Sensor::O.source());
	assert_eq!("w!()",  Sensor::W.source());
}

#[test]
fn should_correctly_source_commands() {
	assert_eq!("skip!()",  Command::Skip.source());
	assert_eq!("left!()",  Command::Left.source());
	assert_eq!("right!()", Command::Right.source());
	assert_eq!("up!()",    Command::Up.source());
}<commit_msg>Document ast::source<commit_after>use super::structure::{Program,Condition,Command,Expression,Sensor};

/// Representation of an `ast::structure::Program`
pub trait Source {
	fn source(&self) -> String;
}

impl Source for Program {
	fn source(&self) -> String {
		match *self {
			Program::If(ref condition, ref left, ref right) => format!("iff!({},{},{})", condition.source(), left.source(), right.source()),
			Program::Command(ref command)                   => command.source(),
		}
	}
}

impl Source for Condition {
	fn source(&self) -> String {
		match *self {
			Condition::True                              => format!("T!()"),
			Condition::False                             => format!("F!()"),
			Condition::Not(ref condition)                => format!("not!({})", (*condition).source()),
			Condition::Or(ref left, ref right)           => format!("or!({},{})", (*left).source(), (*right).source()),
			Condition::And(ref left, ref right)          => format!("and!({},{})", (*left).source(), (*right).source()),

			Condition::Less(ref left, ref right)         => format!("less!({},{})", (*left).source(), (*right).source()),
			Condition::LessEqual(ref left, ref right)    => format!("less_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Equal(ref left, ref right)        => format!("equal!({},{})", (*left).source(), (*right).source()),
			Condition::GreaterEqual(ref left, ref right) => format!("greater_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Greater(ref left, ref right)      => format!("greater!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Expression {
	fn source(&self) -> String {
		match *self {
			Expression::Constant(value)               => format!("constant!({:.*})", 4, value),
			Expression::Sensor(ref sensor)            => sensor.source(),
			Expression::Plus(ref left, ref right)     => format!("plus!({},{})", (*left).source(), (*right).source()),
			Expression::Minus(ref left, ref right)    => format!("minus!({},{})", (*left).source(), (*right).source()),
			Expression::Multiply(ref left, ref right) => format!("multiply!({},{})", (*left).source(), (*right).source()),
			Expression::Divide(ref left, ref right)   => format!("divide!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Sensor {
	fn source(&self) -> String {
		match *self {
			Sensor::X  => format!("x!()"),
			Sensor::Y  => format!("u!()"),
			Sensor::Vx => format!("vx!()"),
			Sensor::Vy => format!("vy!()"),
			Sensor::O  => format!("o!()"),
			Sensor::W  => format!("w!()"),
		}
	}
}

impl Source for Command {
	fn source(&self) -> String {
		match *self {
			Command::Skip  => format!("skip!()"),
			Command::Left  => format!("left!()"),
			Command::Right => format!("right!()"),
			Command::Up    => format!("up!()"),
		}
	}
}

#[test]
fn should_correctly_source_programs() {
	assert_eq!("iff!(T!(),skip!(),left!())",
		Program::If(Condition::True, Box::new(Program::Command(Command::Skip)), Box::new(Program::Command(Command::Left))).source());
	assert_eq!("skip!()", Program::Command(Command::Skip).source());
}

#[test]
fn should_correctly_source_conditions() {
	assert_eq!("T!()", Condition::True.source());
	assert_eq!("F!()", Condition::False.source());
	assert_eq!("not!(T!())", Condition::Not(Box::new(Condition::True)).source());
	assert_eq!("or!(T!(),F!())", Condition::Or(Box::new(Condition::True), Box::new(Condition::False)).source());
	assert_eq!("and!(F!(),T!())", Condition::And(Box::new(Condition::False), Box::new(Condition::True)).source());
	assert_eq!("less!(constant!(1.0000),constant!(2.0000))",
		Condition::Less(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("less_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::LessEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("equal!(constant!(1.0000),constant!(2.0000))",
		Condition::Equal(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::GreaterEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater!(constant!(1.0000),constant!(2.0000))",
		Condition::Greater(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_expressions() {
	assert_eq!("constant!(1.0000)", Expression::Constant(1.0).source());
	assert_eq!("vx!()", Expression::Sensor(Sensor::Vx).source());
	assert_eq!("plus!(constant!(1.0000),vy!())",
		Expression::Plus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Sensor(Sensor::Vy))).source());
	assert_eq!("minus!(constant!(1.0000),constant!(2.0000))",
		Expression::Minus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("multiply!(constant!(1.0000),constant!(2.0000))",
		Expression::Multiply(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("divide!(constant!(1.0000),constant!(2.0000))",
		Expression::Divide(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_sensors() {
	assert_eq!("x!()",  Sensor::X.source());
	assert_eq!("u!()",  Sensor::Y.source());
	assert_eq!("vx!()", Sensor::Vx.source());
	assert_eq!("vy!()", Sensor::Vy.source());
	assert_eq!("o!()",  Sensor::O.source());
	assert_eq!("w!()",  Sensor::W.source());
}

#[test]
fn should_correctly_source_commands() {
	assert_eq!("skip!()",  Command::Skip.source());
	assert_eq!("left!()",  Command::Left.source());
	assert_eq!("right!()", Command::Right.source());
	assert_eq!("up!()",    Command::Up.source());
}<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
pub use optional::Optional;
pub use sensors::{SensorTemplate, Sensors};
pub use sensors::{TemperatureSensor, PeopleNowPresentSensor};

#[derive(Debug, Clone, RustcDecodable)]
pub struct Location {
    pub address: Optional<String>,
    pub lat: f64,
    pub lon: f64,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Spacefed {
    pub spacenet: bool,
    pub spacesaml: bool,
    pub spacephone: bool,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Icon {
    pub open: String,
    pub close: String,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct State {
    pub open: Option<bool>,
    pub lastchange: Optional<u64>,
    pub trigger_person: Optional<String>,
    pub message: Optional<String>,
    pub icon: Optional<Icon>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Event {
    pub name: String,
    pub _type: String,
    pub timestamp: u64,
    pub extra: Optional<String>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Contact {
    pub irc: Optional<String>,
    pub twitter: Optional<String>,
    pub foursquare: Optional<String>,
    pub email: Optional<String>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Feed {
    pub _type: Optional<String>,
    pub url: String,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Feeds {
    pub blog: Optional<Feed>,
    pub wiki: Optional<Feed>,
    pub calendar: Optional<Feed>,
    pub flickr: Optional<Feed>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Cache {
    pub schedule: String,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct RadioShow {
    pub name: String,
    pub url: String,
    pub _type: String,
    pub start: String,
    pub end: String,
}

/// The main Space API status object.
#[derive(Debug, Clone, RustcDecodable)]
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 absolutely required fields.
    pub fn new<S: Into<String>>(space: S, logo: S, url: S, location: Location, contact: Contact, issue_report_channels: Vec<String>) -> Status {
        Status {
            api: "0.13".into(),
            space: space.into(),
            logo: logo.into(),
            url: url.into(),
            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());

        self.spacefed.as_ref().map_or((), |v| { d.insert("spacefed".to_string(), v.to_json()); } );
        self.projects.as_ref().map_or((), |v| { d.insert("projects".to_string(), v.to_json()); });
        self.cam.as_ref().map_or((), |v| { d.insert("cam".to_string(), v.to_json()); });
        self.feeds.as_ref().map_or((), |v| { d.insert("feeds".to_string(), v.to_json()); });
        self.events.as_ref().map_or((), |v| { d.insert("events".to_string(), v.to_json()); });
        self.radio_show.as_ref().map_or((), |v| { d.insert("radio_show".to_string(), v.to_json()); });

        self.cache.as_ref().map_or((), |v| { d.insert("cache".to_string(), v.to_json()); });
        d.insert("issue_report_channels".to_string(), self.issue_report_channels.to_json());

        d.insert("state".to_string(), self.state.to_json());
        self.sensors.as_ref().map_or((), |v| { d.insert("sensors".to_string(), v.to_json()); });

        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());
        self.lastchange.as_ref().map_or((), |v| { d.insert("lastchange".to_string(), v.to_json()); });
        self.trigger_person.as_ref().map_or((), |v| { d.insert("trigger_person".to_string(), v.to_json()); });
        self.message.as_ref().map_or((), |v| { d.insert("message".to_string(), v.to_json()); });
        self.icon.as_ref().map_or((), |v| { d.insert("icon".to_string(), v.to_json()); });
        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());
        self.extra.as_ref().map_or((), |v| { d.insert("extra".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Contact {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.irc.as_ref().map_or((), |v| { d.insert("irc".to_string(), v.to_json()); });
        self.twitter.as_ref().map_or((), |v| { d.insert("twitter".to_string(), v.to_json()); });
        self.foursquare.as_ref().map_or((), |v| { d.insert("foursquare".to_string(), v.to_json()); });
        self.email.as_ref().map_or((), |v| { d.insert("email".to_string(), v.to_json()); });
        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());
        self._type.as_ref().map_or((), |v| { d.insert("type".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Feeds {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.blog.as_ref().map_or((), |v| { d.insert("blog".to_string(), v.to_json()); });
        self.wiki.as_ref().map_or((), |v| { d.insert("wiki".to_string(), v.to_json()); });
        self.calendar.as_ref().map_or((), |v| { d.insert("calendar".to_string(), v.to_json()); });
        self.flickr.as_ref().map_or((), |v| { d.insert("flickr".to_string(), v.to_json()); });
        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>Add tests for serialization/deserialization<commit_after>use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
pub use optional::Optional;
pub use sensors::{SensorTemplate, Sensors};
pub use sensors::{TemperatureSensor, PeopleNowPresentSensor};

#[derive(Debug, Clone, RustcDecodable)]
pub struct Location {
    pub address: Optional<String>,
    pub lat: f64,
    pub lon: f64,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Spacefed {
    pub spacenet: bool,
    pub spacesaml: bool,
    pub spacephone: bool,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Icon {
    pub open: String,
    pub close: String,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct State {
    pub open: Option<bool>,
    pub lastchange: Optional<u64>,
    pub trigger_person: Optional<String>,
    pub message: Optional<String>,
    pub icon: Optional<Icon>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Event {
    pub name: String,
    pub _type: String,
    pub timestamp: u64,
    pub extra: Optional<String>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Contact {
    pub irc: Optional<String>,
    pub twitter: Optional<String>,
    pub foursquare: Optional<String>,
    pub email: Optional<String>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Feed {
    pub _type: Optional<String>,
    pub url: String,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Feeds {
    pub blog: Optional<Feed>,
    pub wiki: Optional<Feed>,
    pub calendar: Optional<Feed>,
    pub flickr: Optional<Feed>,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct Cache {
    pub schedule: String,
}

#[derive(Debug, Clone, RustcDecodable)]
pub struct RadioShow {
    pub name: String,
    pub url: String,
    pub _type: String,
    pub start: String,
    pub end: String,
}

/// The main Space API status object.
#[derive(Debug, Clone, RustcDecodable)]
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 absolutely required fields.
    pub fn new<S: Into<String>>(space: S, logo: S, url: S, location: Location, contact: Contact, issue_report_channels: Vec<String>) -> Status {
        Status {
            api: "0.13".into(),
            space: space.into(),
            logo: logo.into(),
            url: url.into(),
            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());

        self.spacefed.as_ref().map_or((), |v| { d.insert("spacefed".to_string(), v.to_json()); } );
        self.projects.as_ref().map_or((), |v| { d.insert("projects".to_string(), v.to_json()); });
        self.cam.as_ref().map_or((), |v| { d.insert("cam".to_string(), v.to_json()); });
        self.feeds.as_ref().map_or((), |v| { d.insert("feeds".to_string(), v.to_json()); });
        self.events.as_ref().map_or((), |v| { d.insert("events".to_string(), v.to_json()); });
        self.radio_show.as_ref().map_or((), |v| { d.insert("radio_show".to_string(), v.to_json()); });

        self.cache.as_ref().map_or((), |v| { d.insert("cache".to_string(), v.to_json()); });
        d.insert("issue_report_channels".to_string(), self.issue_report_channels.to_json());

        d.insert("state".to_string(), self.state.to_json());
        self.sensors.as_ref().map_or((), |v| { d.insert("sensors".to_string(), v.to_json()); });

        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());
        self.lastchange.as_ref().map_or((), |v| { d.insert("lastchange".to_string(), v.to_json()); });
        self.trigger_person.as_ref().map_or((), |v| { d.insert("trigger_person".to_string(), v.to_json()); });
        self.message.as_ref().map_or((), |v| { d.insert("message".to_string(), v.to_json()); });
        self.icon.as_ref().map_or((), |v| { d.insert("icon".to_string(), v.to_json()); });
        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());
        self.extra.as_ref().map_or((), |v| { d.insert("extra".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Contact {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.irc.as_ref().map_or((), |v| { d.insert("irc".to_string(), v.to_json()); });
        self.twitter.as_ref().map_or((), |v| { d.insert("twitter".to_string(), v.to_json()); });
        self.foursquare.as_ref().map_or((), |v| { d.insert("foursquare".to_string(), v.to_json()); });
        self.email.as_ref().map_or((), |v| { d.insert("email".to_string(), v.to_json()); });
        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());
        self._type.as_ref().map_or((), |v| { d.insert("type".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Feeds {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.blog.as_ref().map_or((), |v| { d.insert("blog".to_string(), v.to_json()); });
        self.wiki.as_ref().map_or((), |v| { d.insert("wiki".to_string(), v.to_json()); });
        self.calendar.as_ref().map_or((), |v| { d.insert("calendar".to_string(), v.to_json()); });
        self.flickr.as_ref().map_or((), |v| { d.insert("flickr".to_string(), v.to_json()); });
        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)
    }
}

#[cfg(test)]
mod test {
  use super::*;
  use optional::Optional::*;
  use rustc_serialize::json::{self, Json, ToJson};

  #[test]
  fn serialize_deserialize_cache() {
    let a :Cache = Cache{ schedule: format!("bla") };
    let b :Cache = json::decode( & a.to_json().to_string() ).unwrap();

    assert_eq!(a.schedule, b.schedule);
  }

  #[test]
  fn serialize_deserialize_contact() {
    let a :Contact = Contact{
      irc: Value(format!("bla")),
      twitter: Absent,
      foursquare: Absent,
      email: Value(format!("bli@bla")),
    };
    let b :Contact = json::decode( & a.to_json().to_string() ).unwrap();

    assert_eq!(a.irc, b.irc);
    assert_eq!(a.twitter, b.twitter);
    assert_eq!(a.foursquare, b.foursquare);
    assert_eq!(a.email, b.email);
  }
}
<|endoftext|>


<commit_before>// Filesystem scanning.

use Result;
use escape::*;
use suretree::{AttMap, SureFile, SureTree};

use std::fs::{self, symlink_metadata, Metadata};
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};
use libc;

pub fn scan_fs<P: AsRef<Path>>(root: P) -> Result<SureTree> {
    let root = root.as_ref().to_path_buf();

    walk_root(&root)
}

fn walk_root(path: &Path) -> Result<SureTree> {
    let meta = symlink_metadata(path)?;

    if !meta.is_dir() {
        return Err(From::from("Root must be a directory"));
    }

    walk(
        "__root__".to_string(),
        path,
        encode_atts(path, &meta),
        &meta,
    )
}

fn walk(my_name: String, path: &Path, my_atts: AttMap, my_meta: &Metadata) -> Result<SureTree> {
    let mut entries = vec![];

    // TODO: Instead of failing everything because of read failure, just
    // fail some things.

    for entry in fs::read_dir(path)? {
        let entry = entry?;
        entries.push(entry);
    }

    // Sort by inode before sorting.  This helps performance on some
    // filesystems (such as ext4).
    entries.sort_by(|a, b| a.ino().cmp(&b.ino()));

    let mut files: Vec<_> = entries
        .iter()
        .filter_map(|e| {
            match e.metadata() {
                Ok(m) => {
                    let path = e.path();
                    let atts = encode_atts(&path, &m);

                    // Check for crossing mountpoints.
                    if m.is_dir() && m.dev() != my_meta.dev() {
                        return None;
                    }

                    Some(OneFile {
                        path: path,
                        meta: m,
                        atts: atts,
                    })
                }
                Err(err) => {
                    error!("Unable to stat file: {:?} ({})", e.path(), err);
                    None
                }
            }
        })
        .collect();

    // Sort them back by name.
    files.sort_by(|a, b| a.path.file_name().cmp(&b.path.file_name()));

    // Build the SureTree data.
    let mut node = SureTree {
        name: my_name,
        atts: my_atts,
        children: Vec::new(),
        files: Vec::new(),
    };

    // Process all of the nodes.
    for ch in files {
        if ch.meta.is_dir() {
            let child_name = ch.path.file_name().unwrap().as_bytes().escaped();
            let child = walk(child_name, &ch.path, ch.atts, &ch.meta)?;
            node.children.push(child);
        } else {
            let child_name = ch.path.file_name().unwrap().as_bytes().escaped();
            let child = SureFile {
                name: child_name,
                atts: ch.atts,
            };
            node.files.push(child);
        }
    }

    Ok(node)
}

// Encode the attributes for the given node.  Note that this returns, even
// when there is an error (resolving a symlink).  It logs an error, and
// returns a placeholder.
fn encode_atts(name: &Path, meta: &Metadata) -> AttMap {
    // let fname = name.file_name().unwrap().as_bytes().escaped();
    let mode = meta.mode() as libc::mode_t & libc::S_IFMT;

    let mut base = AttMap::new();

    // These attributes apply to every node.
    base.insert("uid".to_string(), meta.uid().to_string());
    base.insert("gid".to_string(), meta.gid().to_string());
    base.insert(
        "perm".to_string(),
        (meta.mode() as libc::mode_t & !libc::S_IFMT).to_string(),
    );

    // Other permissions are based on the type of the node.
    match mode as libc::mode_t {
        libc::S_IFDIR => {
            base.insert("kind".to_string(), "dir".to_string());
        }
        libc::S_IFREG => {
            base.insert("kind".to_string(), "file".to_string());
            base.insert("ino".to_string(), meta.ino().to_string());
            base.insert("size".to_string(), meta.size().to_string());
            time_info(&mut base, meta);
            // Note that the 'sha1' attribute is computed later.
        }
        libc::S_IFLNK => {
            base.insert("kind".to_string(), "lnk".to_string());
            let link = match fs::read_link(name) {
                Ok(l) => l,
                Err(err) => {
                    error!("Unable to read link: {:?} ({})", name, err);
                    // TODO: Generate a unique placeholder so this will
                    // always show up.
                    From::from("???")
                }
            };
            base.insert("targ".to_string(), link.as_os_str().as_bytes().escaped());
        }
        libc::S_IFIFO => {
            base.insert("kind".to_string(), "fifo".to_string());
        }
        /* libc::S_IFSOCK */
        0o140000 => {
            base.insert("kind".to_string(), "sock".to_string());
        }
        libc::S_IFCHR => {
            base.insert("kind".to_string(), "chr".to_string());
            add_dev(&mut base, meta);
        }
        libc::S_IFBLK => {
            base.insert("kind".to_string(), "blk".to_string());
            add_dev(&mut base, meta);
        }
        _ => panic!("Unknown file type: 0o{:o}", mode),
    }

    // println!("{:?}: atts: {:?}", fname, base);
    base
}

fn add_dev(base: &mut AttMap, meta: &Metadata) {
    let rdev = meta.rdev();
    // This is defined in a macro, and hasn't made it into libc.  Given how
    // it is defined in the header, it is unlikely to change, at least on
    // Linux.
    base.insert("devmaj".to_string(), ((rdev >> 8) & 0xfff).to_string());
    base.insert("devmin".to_string(), (rdev & 0xff).to_string());
}

fn time_info(base: &mut AttMap, meta: &Metadata) {
    // TODO: Handle the nsec part of the time.
    base.insert("mtime".to_string(), meta.mtime().to_string());
    base.insert("ctime".to_string(), meta.ctime().to_string());
}

// Temp struct to hold information on intermediate files.
struct OneFile {
    path: PathBuf,
    meta: Metadata,
    atts: AttMap,
}
<commit_msg>Use libc::S_IFSOCK<commit_after>// Filesystem scanning.

use Result;
use escape::*;
use suretree::{AttMap, SureFile, SureTree};

use std::fs::{self, symlink_metadata, Metadata};
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};
use libc;

pub fn scan_fs<P: AsRef<Path>>(root: P) -> Result<SureTree> {
    let root = root.as_ref().to_path_buf();

    walk_root(&root)
}

fn walk_root(path: &Path) -> Result<SureTree> {
    let meta = symlink_metadata(path)?;

    if !meta.is_dir() {
        return Err(From::from("Root must be a directory"));
    }

    walk(
        "__root__".to_string(),
        path,
        encode_atts(path, &meta),
        &meta,
    )
}

fn walk(my_name: String, path: &Path, my_atts: AttMap, my_meta: &Metadata) -> Result<SureTree> {
    let mut entries = vec![];

    // TODO: Instead of failing everything because of read failure, just
    // fail some things.

    for entry in fs::read_dir(path)? {
        let entry = entry?;
        entries.push(entry);
    }

    // Sort by inode before sorting.  This helps performance on some
    // filesystems (such as ext4).
    entries.sort_by(|a, b| a.ino().cmp(&b.ino()));

    let mut files: Vec<_> = entries
        .iter()
        .filter_map(|e| {
            match e.metadata() {
                Ok(m) => {
                    let path = e.path();
                    let atts = encode_atts(&path, &m);

                    // Check for crossing mountpoints.
                    if m.is_dir() && m.dev() != my_meta.dev() {
                        return None;
                    }

                    Some(OneFile {
                        path: path,
                        meta: m,
                        atts: atts,
                    })
                }
                Err(err) => {
                    error!("Unable to stat file: {:?} ({})", e.path(), err);
                    None
                }
            }
        })
        .collect();

    // Sort them back by name.
    files.sort_by(|a, b| a.path.file_name().cmp(&b.path.file_name()));

    // Build the SureTree data.
    let mut node = SureTree {
        name: my_name,
        atts: my_atts,
        children: Vec::new(),
        files: Vec::new(),
    };

    // Process all of the nodes.
    for ch in files {
        if ch.meta.is_dir() {
            let child_name = ch.path.file_name().unwrap().as_bytes().escaped();
            let child = walk(child_name, &ch.path, ch.atts, &ch.meta)?;
            node.children.push(child);
        } else {
            let child_name = ch.path.file_name().unwrap().as_bytes().escaped();
            let child = SureFile {
                name: child_name,
                atts: ch.atts,
            };
            node.files.push(child);
        }
    }

    Ok(node)
}

// Encode the attributes for the given node.  Note that this returns, even
// when there is an error (resolving a symlink).  It logs an error, and
// returns a placeholder.
fn encode_atts(name: &Path, meta: &Metadata) -> AttMap {
    // let fname = name.file_name().unwrap().as_bytes().escaped();
    let mode = meta.mode() as libc::mode_t & libc::S_IFMT;

    let mut base = AttMap::new();

    // These attributes apply to every node.
    base.insert("uid".to_string(), meta.uid().to_string());
    base.insert("gid".to_string(), meta.gid().to_string());
    base.insert(
        "perm".to_string(),
        (meta.mode() as libc::mode_t & !libc::S_IFMT).to_string(),
    );

    // Other permissions are based on the type of the node.
    match mode as libc::mode_t {
        libc::S_IFDIR => {
            base.insert("kind".to_string(), "dir".to_string());
        }
        libc::S_IFREG => {
            base.insert("kind".to_string(), "file".to_string());
            base.insert("ino".to_string(), meta.ino().to_string());
            base.insert("size".to_string(), meta.size().to_string());
            time_info(&mut base, meta);
            // Note that the 'sha1' attribute is computed later.
        }
        libc::S_IFLNK => {
            base.insert("kind".to_string(), "lnk".to_string());
            let link = match fs::read_link(name) {
                Ok(l) => l,
                Err(err) => {
                    error!("Unable to read link: {:?} ({})", name, err);
                    // TODO: Generate a unique placeholder so this will
                    // always show up.
                    From::from("???")
                }
            };
            base.insert("targ".to_string(), link.as_os_str().as_bytes().escaped());
        }
        libc::S_IFIFO => {
            base.insert("kind".to_string(), "fifo".to_string());
        }
        libc::S_IFSOCK => {
            base.insert("kind".to_string(), "sock".to_string());
        }
        libc::S_IFCHR => {
            base.insert("kind".to_string(), "chr".to_string());
            add_dev(&mut base, meta);
        }
        libc::S_IFBLK => {
            base.insert("kind".to_string(), "blk".to_string());
            add_dev(&mut base, meta);
        }
        _ => panic!("Unknown file type: 0o{:o}", mode),
    }

    // println!("{:?}: atts: {:?}", fname, base);
    base
}

fn add_dev(base: &mut AttMap, meta: &Metadata) {
    let rdev = meta.rdev();
    // This is defined in a macro, and hasn't made it into libc.  Given how
    // it is defined in the header, it is unlikely to change, at least on
    // Linux.
    base.insert("devmaj".to_string(), ((rdev >> 8) & 0xfff).to_string());
    base.insert("devmin".to_string(), (rdev & 0xff).to_string());
}

fn time_info(base: &mut AttMap, meta: &Metadata) {
    // TODO: Handle the nsec part of the time.
    base.insert("mtime".to_string(), meta.mtime().to_string());
    base.insert("ctime".to_string(), meta.ctime().to_string());
}

// Temp struct to hold information on intermediate files.
struct OneFile {
    path: PathBuf,
    meta: Metadata,
    atts: AttMap,
}
<|endoftext|>


<commit_before>#![allow(missing_docs)]
//! These are inner traits to support methods overloading for the `Client`

use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use time::Duration;
use output::Output;
use playlist::Playlist;
use song::{self, Id, Song};

pub trait ToPlaylistName {
    fn to_name(&self) -> &str;
}

impl ToPlaylistName for Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a String {
    fn to_name(&self) -> &str {
        &*self
    }
}

impl<'a> ToPlaylistName for &'a str {
    fn to_name(&self) -> &str {
        *self
    }
}

impl ToPlaylistName for str {
    fn to_name(&self) -> &str {
        self
    }
}

impl ToPlaylistName for String {
    fn to_name(&self) -> &str {
        &*self
    }
}

pub trait ToSeconds {
    fn to_seconds(self) -> f64;
}

impl ToSeconds for i64 {
    fn to_seconds(self) -> f64 {
        self as f64
    }
}

impl ToSeconds for f64 {
    fn to_seconds(self) -> f64 {
        self
    }
}

impl ToSeconds for Duration {
    fn to_seconds(self) -> f64 {
        self.num_milliseconds() as f64 / 1000.0
    }
}

pub trait IsId {
    fn is_id() -> bool { false }
}

pub trait ToQueueRangeOrPlace : IsId {
    fn to_range(self) -> String;
}

pub trait ToQueueRange {
    fn to_range(self) -> String;
}

impl<T: ToQueuePlace> ToQueueRangeOrPlace for T {
    fn to_range(self) -> String {
        format!("{}", self.to_place())
    }
}

impl ToQueueRange for Range<u32> {
    fn to_range(self) -> String {
        format!("{}:{}", self.start, self.end)
    }
}

impl ToQueueRangeOrPlace for Range<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for RangeTo<u32> {
    fn to_range(self) -> String {
        format!(":{}", self.end)
    }
}

impl ToQueueRangeOrPlace for RangeTo<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for RangeFrom<u32> {
    fn to_range(self) -> String {
        format!("{}:", self.start)
    }
}

impl ToQueueRangeOrPlace for RangeFrom<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for RangeFull {
    fn to_range(self) -> String {
        String::new()
    }
}

impl ToQueueRangeOrPlace for RangeFull {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

pub trait ToQueuePlace : IsId {
    fn to_place(self) -> u32;
}

impl ToQueuePlace for Id {
    fn to_place(self) -> u32 {
        self.0
    }
}

impl ToQueuePlace for u32 {
    fn to_place(self) -> u32 {
        self
    }
}

impl IsId for u32 {}
impl IsId for Range<u32> {}
impl IsId for RangeTo<u32> {}
impl IsId for RangeFrom<u32> {}
impl IsId for RangeFull {}
impl IsId for Id {
    fn is_id() -> bool {
        true
    }
}

pub trait ToOutputId {
    fn to_output_id(self) -> u32;
}

impl ToOutputId for u32 {
    fn to_output_id(self) -> u32 {
        self
    }
}
impl ToOutputId for Output {
    fn to_output_id(self) -> u32 {
        self.id
    }
}

pub trait ToSongRange {
    fn to_range(self) -> song::Range;
}

impl ToSongRange for Range<Duration> {
    fn to_range(self) -> song::Range {
        song::Range(self.start, Some(self.end))
    }
}

impl ToSongRange for Range<u32> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::seconds(self.start as i64), Some(Duration::seconds(self.end as i64)))
    }
}

impl ToSongRange for RangeFrom<Duration> {
    fn to_range(self) -> song::Range {
        song::Range(self.start, None)
    }
}

impl ToSongRange for RangeFrom<u32> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::seconds(self.start as i64), None)
    }
}

impl ToSongRange for RangeTo<Duration> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::zero(), Some(self.end))
    }
}

impl ToSongRange for RangeTo<u32> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::zero(), Some(Duration::seconds(self.end as i64)))
    }
}

impl ToSongRange for RangeFull {
    fn to_range(self) -> song::Range {
        song::Range(Duration::zero(), None)
    }
}

impl ToSongRange for song::Range {
    fn to_range(self) -> song::Range {
        self
    }
}

pub trait ToSongId {
    fn to_song_id(&self) -> Id;
}

impl ToSongId for Song {
    fn to_song_id(&self) -> Id {
        self.place.unwrap().id
    }
}

impl ToSongId for u32 {
    fn to_song_id(&self) -> Id {
        Id(*self)
    }
}

impl ToSongId for Id {
    fn to_song_id(&self) -> Id {
        *self
    }
}
<commit_msg>inner traits code cleanup<commit_after>#![allow(missing_docs)]
//! These are inner traits to support methods overloading for the `Client`

use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use time::Duration;
use output::Output;
use playlist::Playlist;
use song::{self, Id, Song};

// Playlist name polymorphisms {{{
pub trait ToPlaylistName {
    fn to_name(&self) -> &str;
}

impl ToPlaylistName for Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a String {
    fn to_name(&self) -> &str {
        &*self
    }
}

impl<'a> ToPlaylistName for &'a str {
    fn to_name(&self) -> &str {
        *self
    }
}

impl ToPlaylistName for str {
    fn to_name(&self) -> &str {
        self
    }
}

impl ToPlaylistName for String {
    fn to_name(&self) -> &str {
        &*self
    }
}
// }}}

// Seconds polymorphisms {{{
pub trait ToSeconds {
    fn to_seconds(self) -> f64;
}

impl ToSeconds for i64 {
    fn to_seconds(self) -> f64 {
        self as f64
    }
}

impl ToSeconds for f64 {
    fn to_seconds(self) -> f64 {
        self
    }
}

impl ToSeconds for Duration {
    fn to_seconds(self) -> f64 {
        self.num_milliseconds() as f64 / 1000.0
    }
}
// }}}

// Queue place polymorphisms {{{

pub trait IsId {
    fn is_id() -> bool { false }
}

pub trait ToQueueRangeOrPlace : IsId {
    fn to_range(self) -> String;
}

pub trait ToQueueRange {
    fn to_range(self) -> String;
}

impl<T: ToQueuePlace> ToQueueRangeOrPlace for T {
    fn to_range(self) -> String {
        format!("{}", self.to_place())
    }
}

impl ToQueueRange for Range<u32> {
    fn to_range(self) -> String {
        format!("{}:{}", self.start, self.end)
    }
}

impl ToQueueRangeOrPlace for Range<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for RangeTo<u32> {
    fn to_range(self) -> String {
        format!(":{}", self.end)
    }
}

impl ToQueueRangeOrPlace for RangeTo<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for RangeFrom<u32> {
    fn to_range(self) -> String {
        format!("{}:", self.start)
    }
}

impl ToQueueRangeOrPlace for RangeFrom<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for RangeFull {
    fn to_range(self) -> String {
        String::new()
    }
}

impl ToQueueRangeOrPlace for RangeFull {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

pub trait ToQueuePlace : IsId {
    fn to_place(self) -> u32;
}

impl ToQueuePlace for Id {
    fn to_place(self) -> u32 {
        self.0
    }
}

impl ToQueuePlace for u32 {
    fn to_place(self) -> u32 {
        self
    }
}

impl IsId for u32 {}
impl IsId for Range<u32> {}
impl IsId for RangeTo<u32> {}
impl IsId for RangeFrom<u32> {}
impl IsId for RangeFull {}
impl IsId for Id {
    fn is_id() -> bool {
        true
    }
}

pub trait ToSongId {
    fn to_song_id(&self) -> Id;
}

impl ToSongId for Song {
    fn to_song_id(&self) -> Id {
        self.place.unwrap().id
    }
}

impl ToSongId for u32 {
    fn to_song_id(&self) -> Id {
        Id(*self)
    }
}

impl ToSongId for Id {
    fn to_song_id(&self) -> Id {
        *self
    }
}
// }}}

// Output id polymorphisms {{{
pub trait ToOutputId {
    fn to_output_id(self) -> u32;
}

impl ToOutputId for u32 {
    fn to_output_id(self) -> u32 {
        self
    }
}
impl ToOutputId for Output {
    fn to_output_id(self) -> u32 {
        self.id
    }
}
// }}}

// Song play range polymorphisms {{{
pub trait ToSongRange {
    fn to_range(self) -> song::Range;
}

impl ToSongRange for Range<Duration> {
    fn to_range(self) -> song::Range {
        song::Range(self.start, Some(self.end))
    }
}

impl ToSongRange for Range<u32> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::seconds(self.start as i64), Some(Duration::seconds(self.end as i64)))
    }
}

impl ToSongRange for RangeFrom<Duration> {
    fn to_range(self) -> song::Range {
        song::Range(self.start, None)
    }
}

impl ToSongRange for RangeFrom<u32> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::seconds(self.start as i64), None)
    }
}

impl ToSongRange for RangeTo<Duration> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::zero(), Some(self.end))
    }
}

impl ToSongRange for RangeTo<u32> {
    fn to_range(self) -> song::Range {
        song::Range(Duration::zero(), Some(Duration::seconds(self.end as i64)))
    }
}

impl ToSongRange for RangeFull {
    fn to_range(self) -> song::Range {
        song::Range(Duration::zero(), None)
    }
}

impl ToSongRange for song::Range {
    fn to_range(self) -> song::Range {
        self
    }
}
// }}}

<|endoftext|>


<commit_before>use std::ops::{
  Add, AddAssign,
  Sub, SubAssign,
  Mul, MulAssign,
  Div, DivAssign,
  Index, IndexMut,
};

#[derive(Debug, Copy, Clone)]
pub struct Vec3 {
  pub i : f64,
  pub j : f64,
  pub k : f64,
}

impl Vec3 {
  pub fn length(&self) -> f64 {
    (self.i * self.i + self.j * self.j + self.k * self.k).sqrt()
  }
  pub fn dot(&self, other: Vec3) -> f64 {
    self.i * other.i + self.j * other.j + self.k * other.k
  }
}

impl Add for Vec3 {
  type Output = Vec3;
  fn add(self, other: Vec3) -> Vec3 {
      Vec3 {i: self.i + other.i, j: self.j + other.j, k: self.k + other.k}
  }
}

impl AddAssign for Vec3 {
  fn add_assign(&mut self, other: Vec3) {
    *self = Vec3 {
      i: self.i + other.i,
      j: self.j + other.j,
      k: self.k + other.k,
    };
  }
}

impl Sub for Vec3 {
  type Output = Vec3;
  fn sub(self, other: Vec3) -> Vec3 {
      Vec3 {i: self.i - other.i, j: self.j - other.j, k: self.k - other.k}
  }
}

impl SubAssign for Vec3 {
  fn sub_assign(&mut self, other: Vec3) {
    *self = Vec3 {
      i: self.i - other.i,
      j: self.j - other.j,
      k: self.k - other.k,
    }
  }
}

impl Mul<Vec3> for Vec3 {
  type Output = Vec3;
  fn mul(self, rhs: Vec3) -> Vec3 {
    Vec3 {i: self.i * rhs.i, j: self.j * rhs.j, k: self.k * rhs.k}
  }
}

impl Mul<f64> for Vec3 {
  type Output = Vec3;
  fn mul(self, scalar: f64) -> Vec3 {
    Vec3 {i: self.i * scalar, j: self.j * scalar, k: self.k * scalar}
  }
}

impl MulAssign<Vec3> for Vec3 {
  fn mul_assign(&mut self, rhs: Vec3) {
    *self = Vec3 {
      i: self.i * rhs.i,
      j: self.j * rhs.j,
      k: self.k * rhs.k,
    }
  }
}

impl MulAssign<f64> for Vec3 {
  fn mul_assign(&mut self, scalar: f64) {
    *self = Vec3 {
      i: self.i * scalar,
      j: self.j * scalar,
      k: self.k * scalar,
    }
  }
}

impl Div<Vec3> for Vec3 {
  type Output = Vec3;
  fn div(self, rhs: Vec3) -> Vec3 {
    Vec3 {i: self.i / rhs.i, j: self.j / rhs.j, k: self.k / rhs.k}
  }
}

impl Div<f64> for Vec3 {
  type Output = Vec3;
  fn div(self, scalar: f64) -> Vec3 {
    Vec3 {i: self.i / scalar, j: self.j / scalar, k: self.k / scalar}
  }
}

impl DivAssign<Vec3> for Vec3 {
  fn div_assign(&mut self, rhs: Vec3) {
    *self = Vec3 {
      i: self.i / rhs.i,
      j: self.j / rhs.j,
      k: self.k / rhs.k,
    }
  }
}

impl DivAssign<f64> for Vec3 {
  fn div_assign(&mut self, scalar: f64) {
    *self = Vec3 {
      i: self.i / scalar,
      j: self.j / scalar,
      k: self.k / scalar,
    }
  }
}

impl Index<i32> for Vec3 {
  type Output = f64;
  fn index(&self, idx: i32) -> &f64 {
    match idx {
      0 => &self.i,
      1 => &self.j,
      2 => &self.k,
      _ => panic!("index out of range: {}", idx),
    }
  }
}

impl IndexMut<i32> for Vec3 {
  fn index_mut<'a>(&'a mut self, idx: i32) -> &'a mut f64 {
    match idx {
      0 => &mut self.i,
      1 => &mut self.j,
      2 => &mut self.k,
      _ => panic!("index out of range: {}", idx),
    }
  }
}

#[cfg(test)]
mod should {
  use super::Vec3;
  #[test]
  fn add() {
    let v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let sum = v1 + v2;
    assert_eq!(sum.i, 3.0);
    assert_eq!(sum.j, 3.0);
    assert_eq!(sum.k, 3.0);
  }
  #[test]
  fn add_assign() {
    let mut v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1 += v2;
    assert_eq!(v1.i, 3.0);
    assert_eq!(v1.j, 3.0);
    assert_eq!(v1.k, 3.0);
  }
  #[test]
  fn subtract() {
    let v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let diff = v1 - v2;
    assert_eq!(diff.i, -1.0);
    assert_eq!(diff.j, -1.0);
    assert_eq!(diff.k, -1.0);
  }
  #[test]
  fn subtract_assign() {
    let mut v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1 -= v2;
    assert_eq!(v1.i, -1.0);
    assert_eq!(v1.j, -1.0);
    assert_eq!(v1.k, -1.0);
  }
  #[test]
  fn multiply_by_vec3_elementwise() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    let product = v1 * v2;
    assert_eq!(product.i, 6.0);
    assert_eq!(product.j, 6.0);
    assert_eq!(product.k, 6.0);
  }
  #[test]
  fn multiply_by_vec3_assign_elementwise() {
    let mut v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    v1 *= v2;
    assert_eq!(v1.i, 6.0);
    assert_eq!(v1.j, 6.0);
    assert_eq!(v1.k, 6.0);
  }
  #[test]
  fn multiply_by_f64() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let product = v1 * 3.0;

    assert_eq!(product.i, 6.0);
    assert_eq!(product.j, 6.0);
    assert_eq!(product.k, 6.0);
  }
  #[test]
  fn multiply_by_f64_assign() {
    let mut v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1 *= 3.0;

    assert_eq!(v1.i, 6.0);
    assert_eq!(v1.j, 6.0);
    assert_eq!(v1.k, 6.0);
  }
  #[test]
  fn divide_by_vec3_elementwise() {
    let v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    let quotient = v1 / v2;
    assert_eq!(quotient.i, 2.0);
    assert_eq!(quotient.j, 2.0);
    assert_eq!(quotient.k, 2.0);
  }
  #[test]
  fn divide_by_vec3_assign_elementwise() {
    let mut v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    v1 /= v2;
    assert_eq!(v1.i, 2.0);
    assert_eq!(v1.j, 2.0);
    assert_eq!(v1.k, 2.0);
  }
  #[test]
  fn divide_by_f64() {
    let v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    let quotient = v1 / 3.0;

    assert_eq!(quotient.i, 2.0);
    assert_eq!(quotient.j, 2.0);
    assert_eq!(quotient.k, 2.0);
  }
  #[test]
  fn divide_by_f64_assign() {
    let mut v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    v1 /= 3.0;

    assert_eq!(v1.i, 2.0);
    assert_eq!(v1.j, 2.0);
    assert_eq!(v1.k, 2.0);
  }
  #[test]
  fn allow_index_access() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};

    assert_eq!(v1[0], 2.0);
    assert_eq!(v1[1], 2.0);
    assert_eq!(v1[2], 2.0);
  }
  #[test]
  #[should_panic(expected = "index out of range: 9")]
  fn panic_on_bad_index() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};

    assert_eq!(v1[9], 2.0);
  }
  #[test]
  fn allow_index_mut_access() {
    let mut v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1[0] = 9.0;

    assert_eq!(v1[0], 9.0);
    assert_eq!(v1[1], 2.0);
    assert_eq!(v1[2], 2.0);
  }

  #[test]
  fn calculate_length() {
    let v1 = Vec3 { i: 4.0, j: 4.0, k: 2.0};

    assert_eq!(v1.length(), 6.0);
  }
  #[test]
  fn calculate_length_with_some_zeros() {
    let v2 = Vec3 { i: 4.0, j: 0.0, k: 0.0};

    assert_eq!(v2.length(), 4.0);
  }
  #[test]
  fn calculate_length_for_zero_vector() {
    let v2 = Vec3 { i: 0.0, j: 0.0, k: 0.0};

    assert_eq!(v2.length(), 0.0);
  }
  #[test]
  fn calculate_dot_product() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};

    let product = v1.dot(v2);

    assert_eq!(product, 18.0);
  }
}<commit_msg>Add cross function and basic test<commit_after>use std::ops::{
  Add, AddAssign,
  Sub, SubAssign,
  Mul, MulAssign,
  Div, DivAssign,
  Index, IndexMut,
};

#[derive(Debug, Copy, Clone)]
pub struct Vec3 {
  pub i : f64,
  pub j : f64,
  pub k : f64,
}

impl Vec3 {
  pub fn length(&self) -> f64 {
    (self.i * self.i + self.j * self.j + self.k * self.k).sqrt()
  }
  pub fn dot(&self, other: Vec3) -> f64 {
    self.i * other.i + self.j * other.j + self.k * other.k
  }
  pub fn cross(&self, other: Vec3) -> Vec3 {
    return Vec3 {
      i: self.j * other.k - self.k * other.j,
      j: -(self.i * other.k - self.k * other.i),
      k: self.i * other.j - self.j * other.i,
    };
  }
}

impl Add for Vec3 {
  type Output = Vec3;
  fn add(self, other: Vec3) -> Vec3 {
      Vec3 {i: self.i + other.i, j: self.j + other.j, k: self.k + other.k}
  }
}

impl AddAssign for Vec3 {
  fn add_assign(&mut self, other: Vec3) {
    *self = Vec3 {
      i: self.i + other.i,
      j: self.j + other.j,
      k: self.k + other.k,
    };
  }
}

impl Sub for Vec3 {
  type Output = Vec3;
  fn sub(self, other: Vec3) -> Vec3 {
      Vec3 {i: self.i - other.i, j: self.j - other.j, k: self.k - other.k}
  }
}

impl SubAssign for Vec3 {
  fn sub_assign(&mut self, other: Vec3) {
    *self = Vec3 {
      i: self.i - other.i,
      j: self.j - other.j,
      k: self.k - other.k,
    }
  }
}

impl Mul<Vec3> for Vec3 {
  type Output = Vec3;
  fn mul(self, rhs: Vec3) -> Vec3 {
    Vec3 {i: self.i * rhs.i, j: self.j * rhs.j, k: self.k * rhs.k}
  }
}

impl Mul<f64> for Vec3 {
  type Output = Vec3;
  fn mul(self, scalar: f64) -> Vec3 {
    Vec3 {i: self.i * scalar, j: self.j * scalar, k: self.k * scalar}
  }
}

impl MulAssign<Vec3> for Vec3 {
  fn mul_assign(&mut self, rhs: Vec3) {
    *self = Vec3 {
      i: self.i * rhs.i,
      j: self.j * rhs.j,
      k: self.k * rhs.k,
    }
  }
}

impl MulAssign<f64> for Vec3 {
  fn mul_assign(&mut self, scalar: f64) {
    *self = Vec3 {
      i: self.i * scalar,
      j: self.j * scalar,
      k: self.k * scalar,
    }
  }
}

impl Div<Vec3> for Vec3 {
  type Output = Vec3;
  fn div(self, rhs: Vec3) -> Vec3 {
    Vec3 {i: self.i / rhs.i, j: self.j / rhs.j, k: self.k / rhs.k}
  }
}

impl Div<f64> for Vec3 {
  type Output = Vec3;
  fn div(self, scalar: f64) -> Vec3 {
    Vec3 {i: self.i / scalar, j: self.j / scalar, k: self.k / scalar}
  }
}

impl DivAssign<Vec3> for Vec3 {
  fn div_assign(&mut self, rhs: Vec3) {
    *self = Vec3 {
      i: self.i / rhs.i,
      j: self.j / rhs.j,
      k: self.k / rhs.k,
    }
  }
}

impl DivAssign<f64> for Vec3 {
  fn div_assign(&mut self, scalar: f64) {
    *self = Vec3 {
      i: self.i / scalar,
      j: self.j / scalar,
      k: self.k / scalar,
    }
  }
}

impl Index<i32> for Vec3 {
  type Output = f64;
  fn index(&self, idx: i32) -> &f64 {
    match idx {
      0 => &self.i,
      1 => &self.j,
      2 => &self.k,
      _ => panic!("index out of range: {}", idx),
    }
  }
}

impl IndexMut<i32> for Vec3 {
  fn index_mut<'a>(&'a mut self, idx: i32) -> &'a mut f64 {
    match idx {
      0 => &mut self.i,
      1 => &mut self.j,
      2 => &mut self.k,
      _ => panic!("index out of range: {}", idx),
    }
  }
}

#[cfg(test)]
mod should {
  use super::Vec3;
  #[test]
  fn add() {
    let v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let sum = v1 + v2;
    assert_eq!(sum.i, 3.0);
    assert_eq!(sum.j, 3.0);
    assert_eq!(sum.k, 3.0);
  }
  #[test]
  fn add_assign() {
    let mut v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1 += v2;
    assert_eq!(v1.i, 3.0);
    assert_eq!(v1.j, 3.0);
    assert_eq!(v1.k, 3.0);
  }
  #[test]
  fn subtract() {
    let v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let diff = v1 - v2;
    assert_eq!(diff.i, -1.0);
    assert_eq!(diff.j, -1.0);
    assert_eq!(diff.k, -1.0);
  }
  #[test]
  fn subtract_assign() {
    let mut v1 = Vec3 { i: 1.0, j: 1.0, k: 1.0};
    let v2 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1 -= v2;
    assert_eq!(v1.i, -1.0);
    assert_eq!(v1.j, -1.0);
    assert_eq!(v1.k, -1.0);
  }
  #[test]
  fn multiply_by_vec3_elementwise() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    let product = v1 * v2;
    assert_eq!(product.i, 6.0);
    assert_eq!(product.j, 6.0);
    assert_eq!(product.k, 6.0);
  }
  #[test]
  fn multiply_by_vec3_assign_elementwise() {
    let mut v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    v1 *= v2;
    assert_eq!(v1.i, 6.0);
    assert_eq!(v1.j, 6.0);
    assert_eq!(v1.k, 6.0);
  }
  #[test]
  fn multiply_by_f64() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let product = v1 * 3.0;

    assert_eq!(product.i, 6.0);
    assert_eq!(product.j, 6.0);
    assert_eq!(product.k, 6.0);
  }
  #[test]
  fn multiply_by_f64_assign() {
    let mut v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1 *= 3.0;

    assert_eq!(v1.i, 6.0);
    assert_eq!(v1.j, 6.0);
    assert_eq!(v1.k, 6.0);
  }
  #[test]
  fn divide_by_vec3_elementwise() {
    let v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    let quotient = v1 / v2;
    assert_eq!(quotient.i, 2.0);
    assert_eq!(quotient.j, 2.0);
    assert_eq!(quotient.k, 2.0);
  }
  #[test]
  fn divide_by_vec3_assign_elementwise() {
    let mut v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};
    v1 /= v2;
    assert_eq!(v1.i, 2.0);
    assert_eq!(v1.j, 2.0);
    assert_eq!(v1.k, 2.0);
  }
  #[test]
  fn divide_by_f64() {
    let v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    let quotient = v1 / 3.0;

    assert_eq!(quotient.i, 2.0);
    assert_eq!(quotient.j, 2.0);
    assert_eq!(quotient.k, 2.0);
  }
  #[test]
  fn divide_by_f64_assign() {
    let mut v1 = Vec3 { i: 6.0, j: 6.0, k: 6.0};
    v1 /= 3.0;

    assert_eq!(v1.i, 2.0);
    assert_eq!(v1.j, 2.0);
    assert_eq!(v1.k, 2.0);
  }
  #[test]
  fn allow_index_access() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};

    assert_eq!(v1[0], 2.0);
    assert_eq!(v1[1], 2.0);
    assert_eq!(v1[2], 2.0);
  }
  #[test]
  #[should_panic(expected = "index out of range: 9")]
  fn panic_on_bad_index() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};

    assert_eq!(v1[9], 2.0);
  }
  #[test]
  fn allow_index_mut_access() {
    let mut v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    v1[0] = 9.0;

    assert_eq!(v1[0], 9.0);
    assert_eq!(v1[1], 2.0);
    assert_eq!(v1[2], 2.0);
  }

  #[test]
  fn calculate_length() {
    let v1 = Vec3 { i: 4.0, j: 4.0, k: 2.0};

    assert_eq!(v1.length(), 6.0);
  }
  #[test]
  fn calculate_length_with_some_zeros() {
    let v2 = Vec3 { i: 4.0, j: 0.0, k: 0.0};

    assert_eq!(v2.length(), 4.0);
  }
  #[test]
  fn calculate_length_for_zero_vector() {
    let v2 = Vec3 { i: 0.0, j: 0.0, k: 0.0};

    assert_eq!(v2.length(), 0.0);
  }
  #[test]
  fn calculate_dot_product() {
    let v1 = Vec3 { i: 2.0, j: 2.0, k: 2.0};
    let v2 = Vec3 { i: 3.0, j: 3.0, k: 3.0};

    let product = v1.dot(v2);

    assert_eq!(product, 18.0);
  }
  #[test]
  fn calculate_cross_product() {
    let v1 = Vec3 { i: 1.0, j: 0.0, k: 0.0};
    let v2 = Vec3 { i: 0.0, j: 1.0, k: 0.0};

    let product = v1.cross(v2);

    assert_eq!(product[0], 0.0);
    assert_eq!(product[1], 0.0);
    assert_eq!(product[2], 1.0);
  }
}<|endoftext|>