<commit_before>use std::mem;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;

use crossbeam_utils::atomic::AtomicCell;

#[test]
fn is_lock_free() {
    struct UsizeWrap(usize);
    struct U8Wrap(bool);
    struct I16Wrap(i16);
    #[repr(align(8))]
    struct U64Align8(u64);

    assert!(AtomicCell::<usize>::is_lock_free());
    assert!(AtomicCell::<isize>::is_lock_free());
    assert!(AtomicCell::<UsizeWrap>::is_lock_free());

    assert!(AtomicCell::<()>::is_lock_free());

    assert!(AtomicCell::<u8>::is_lock_free());
    assert!(AtomicCell::<i8>::is_lock_free());
    assert!(AtomicCell::<bool>::is_lock_free());
    assert!(AtomicCell::<U8Wrap>::is_lock_free());

    assert!(AtomicCell::<u16>::is_lock_free());
    assert!(AtomicCell::<i16>::is_lock_free());
    assert!(AtomicCell::<I16Wrap>::is_lock_free());

    assert!(AtomicCell::<u32>::is_lock_free());
    assert!(AtomicCell::<i32>::is_lock_free());

    // Sizes of both types must be equal, and the alignment of `u64` must be greater or equal than
    // that of `AtomicU64`. In i686-unknown-linux-gnu, the alignment of `u64` is `4` and alignment
    // of `AtomicU64` is `8`, so `AtomicCell<u64>` is not lock-free.
    assert_eq!(
        AtomicCell::<u64>::is_lock_free(),
        cfg!(not(crossbeam_no_atomic_64))
            && cfg!(any(
                target_pointer_width = "64",
                target_pointer_width = "128"
            ))
    );
    assert_eq!(mem::size_of::<U64Align8>(), 8);
    assert_eq!(mem::align_of::<U64Align8>(), 8);
    assert_eq!(
        AtomicCell::<U64Align8>::is_lock_free(),
        cfg!(not(crossbeam_no_atomic_64))
    );

    // AtomicU128 is unstable
    assert!(!AtomicCell::<u128>::is_lock_free());
}

#[test]
fn const_is_lock_free() {
    const _U: bool = AtomicCell::<usize>::is_lock_free();
    const _I: bool = AtomicCell::<isize>::is_lock_free();
}

#[test]
fn drops_unit() {
    static CNT: AtomicUsize = AtomicUsize::new(0);
    CNT.store(0, SeqCst);

    #[derive(Debug, PartialEq, Eq)]
    struct Foo();

    impl Foo {
        fn new() -> Foo {
            CNT.fetch_add(1, SeqCst);
            Foo()
        }
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            CNT.fetch_sub(1, SeqCst);
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new()
        }
    }

    let a = AtomicCell::new(Foo::new());

    assert_eq!(a.swap(Foo::new()), Foo::new());
    assert_eq!(CNT.load(SeqCst), 1);

    a.store(Foo::new());
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new());
    assert_eq!(CNT.load(SeqCst), 1);

    drop(a);
    assert_eq!(CNT.load(SeqCst), 0);
}

#[test]
fn drops_u8() {
    static CNT: AtomicUsize = AtomicUsize::new(0);
    CNT.store(0, SeqCst);

    #[derive(Debug, PartialEq, Eq)]
    struct Foo(u8);

    impl Foo {
        fn new(val: u8) -> Foo {
            CNT.fetch_add(1, SeqCst);
            Foo(val)
        }
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            CNT.fetch_sub(1, SeqCst);
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new(0)
        }
    }

    let a = AtomicCell::new(Foo::new(5));

    assert_eq!(a.swap(Foo::new(6)), Foo::new(5));
    assert_eq!(a.swap(Foo::new(1)), Foo::new(6));
    assert_eq!(CNT.load(SeqCst), 1);

    a.store(Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(0));
    assert_eq!(CNT.load(SeqCst), 1);

    drop(a);
    assert_eq!(CNT.load(SeqCst), 0);
}

#[test]
fn drops_usize() {
    static CNT: AtomicUsize = AtomicUsize::new(0);
    CNT.store(0, SeqCst);

    #[derive(Debug, PartialEq, Eq)]
    struct Foo(usize);

    impl Foo {
        fn new(val: usize) -> Foo {
            CNT.fetch_add(1, SeqCst);
            Foo(val)
        }
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            CNT.fetch_sub(1, SeqCst);
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new(0)
        }
    }

    let a = AtomicCell::new(Foo::new(5));

    assert_eq!(a.swap(Foo::new(6)), Foo::new(5));
    assert_eq!(a.swap(Foo::new(1)), Foo::new(6));
    assert_eq!(CNT.load(SeqCst), 1);

    a.store(Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(0));
    assert_eq!(CNT.load(SeqCst), 1);

    drop(a);
    assert_eq!(CNT.load(SeqCst), 0);
}

#[test]
fn modular_u8() {
    #[derive(Clone, Copy, Eq, Debug, Default)]
    struct Foo(u8);

    impl PartialEq for Foo {
        fn eq(&self, other: &Foo) -> bool {
            self.0 % 5 == other.0 % 5
        }
    }

    let a = AtomicCell::new(Foo(1));

    assert_eq!(a.load(), Foo(1));
    assert_eq!(a.swap(Foo(2)), Foo(11));
    assert_eq!(a.load(), Foo(52));

    a.store(Foo(0));
    assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100)));
    assert_eq!(a.load().0, 5);
    assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100)));
    assert_eq!(a.load().0, 15);
}

#[test]
fn modular_usize() {
    #[derive(Clone, Copy, Eq, Debug, Default)]
    struct Foo(usize);

    impl PartialEq for Foo {
        fn eq(&self, other: &Foo) -> bool {
            self.0 % 5 == other.0 % 5
        }
    }

    let a = AtomicCell::new(Foo(1));

    assert_eq!(a.load(), Foo(1));
    assert_eq!(a.swap(Foo(2)), Foo(11));
    assert_eq!(a.load(), Foo(52));

    a.store(Foo(0));
    assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100)));
    assert_eq!(a.load().0, 5);
    assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100)));
    assert_eq!(a.load().0, 15);
}

#[test]
fn garbage_padding() {
    #[derive(Copy, Clone, Eq, PartialEq)]
    struct Object {
        a: i64,
        b: i32,
    }

    let cell = AtomicCell::new(Object { a: 0, b: 0 });
    let _garbage = [0xfe, 0xfe, 0xfe, 0xfe, 0xfe]; // Needed
    let next = Object { a: 0, b: 0 };

    let prev = cell.load();
    assert!(cell.compare_exchange(prev, next).is_ok());
    println!();
}

#[test]
fn const_atomic_cell_new() {
    static CELL: AtomicCell<usize> = AtomicCell::new(0);

    CELL.store(1);
    assert_eq!(CELL.load(), 1);
}

// https://github.com/crossbeam-rs/crossbeam/pull/767
macro_rules! test_arithmetic {
    ($test_name:ident, $ty:ident) => {
        #[test]
        fn $test_name() {
            let a: AtomicCell<$ty> = AtomicCell::new(7);

            assert_eq!(a.fetch_add(3), 7);
            assert_eq!(a.load(), 10);

            assert_eq!(a.fetch_sub(3), 10);
            assert_eq!(a.load(), 7);

            assert_eq!(a.fetch_and(3), 7);
            assert_eq!(a.load(), 3);

            assert_eq!(a.fetch_or(16), 3);
            assert_eq!(a.load(), 19);

            assert_eq!(a.fetch_xor(2), 19);
            assert_eq!(a.load(), 17);

            assert_eq!(a.fetch_max(18), 17);
            assert_eq!(a.load(), 18);

            assert_eq!(a.fetch_min(17), 18);
            assert_eq!(a.load(), 17);

            assert_eq!(a.fetch_nand(7), 17);
            assert_eq!(a.load(), !(17 & 7));
        }
    };
}
test_arithmetic!(arithmetic_u8, u8);
test_arithmetic!(arithmetic_i8, i8);
test_arithmetic!(arithmetic_u16, u16);
test_arithmetic!(arithmetic_i16, i16);
test_arithmetic!(arithmetic_u32, u32);
test_arithmetic!(arithmetic_i32, i32);
test_arithmetic!(arithmetic_u64, u64);
test_arithmetic!(arithmetic_i64, i64);
test_arithmetic!(arithmetic_u128, u128);
test_arithmetic!(arithmetic_i128, i128);

// https://github.com/crossbeam-rs/crossbeam/issues/748
#[cfg_attr(miri, ignore)] // TODO
#[rustversion::since(1.37)] // #[repr(align(N))] requires Rust 1.37
#[test]
fn issue_748() {
    #[allow(dead_code)]
    #[repr(align(8))]
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    enum Test {
        Field(u32),
        FieldLess,
    }

    assert_eq!(mem::size_of::<Test>(), 8);
    assert_eq!(
        AtomicCell::<Test>::is_lock_free(),
        cfg!(not(crossbeam_no_atomic_64))
    );
    let x = AtomicCell::new(Test::FieldLess);
    assert_eq!(x.load(), Test::FieldLess);
}
<commit_msg>Add test for issue 833<commit_after>use std::mem;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;

use crossbeam_utils::atomic::AtomicCell;

#[test]
fn is_lock_free() {
    struct UsizeWrap(usize);
    struct U8Wrap(bool);
    struct I16Wrap(i16);
    #[repr(align(8))]
    struct U64Align8(u64);

    assert!(AtomicCell::<usize>::is_lock_free());
    assert!(AtomicCell::<isize>::is_lock_free());
    assert!(AtomicCell::<UsizeWrap>::is_lock_free());

    assert!(AtomicCell::<()>::is_lock_free());

    assert!(AtomicCell::<u8>::is_lock_free());
    assert!(AtomicCell::<i8>::is_lock_free());
    assert!(AtomicCell::<bool>::is_lock_free());
    assert!(AtomicCell::<U8Wrap>::is_lock_free());

    assert!(AtomicCell::<u16>::is_lock_free());
    assert!(AtomicCell::<i16>::is_lock_free());
    assert!(AtomicCell::<I16Wrap>::is_lock_free());

    assert!(AtomicCell::<u32>::is_lock_free());
    assert!(AtomicCell::<i32>::is_lock_free());

    // Sizes of both types must be equal, and the alignment of `u64` must be greater or equal than
    // that of `AtomicU64`. In i686-unknown-linux-gnu, the alignment of `u64` is `4` and alignment
    // of `AtomicU64` is `8`, so `AtomicCell<u64>` is not lock-free.
    assert_eq!(
        AtomicCell::<u64>::is_lock_free(),
        cfg!(not(crossbeam_no_atomic_64))
            && cfg!(any(
                target_pointer_width = "64",
                target_pointer_width = "128"
            ))
    );
    assert_eq!(mem::size_of::<U64Align8>(), 8);
    assert_eq!(mem::align_of::<U64Align8>(), 8);
    assert_eq!(
        AtomicCell::<U64Align8>::is_lock_free(),
        cfg!(not(crossbeam_no_atomic_64))
    );

    // AtomicU128 is unstable
    assert!(!AtomicCell::<u128>::is_lock_free());
}

#[test]
fn const_is_lock_free() {
    const _U: bool = AtomicCell::<usize>::is_lock_free();
    const _I: bool = AtomicCell::<isize>::is_lock_free();
}

#[test]
fn drops_unit() {
    static CNT: AtomicUsize = AtomicUsize::new(0);
    CNT.store(0, SeqCst);

    #[derive(Debug, PartialEq, Eq)]
    struct Foo();

    impl Foo {
        fn new() -> Foo {
            CNT.fetch_add(1, SeqCst);
            Foo()
        }
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            CNT.fetch_sub(1, SeqCst);
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new()
        }
    }

    let a = AtomicCell::new(Foo::new());

    assert_eq!(a.swap(Foo::new()), Foo::new());
    assert_eq!(CNT.load(SeqCst), 1);

    a.store(Foo::new());
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new());
    assert_eq!(CNT.load(SeqCst), 1);

    drop(a);
    assert_eq!(CNT.load(SeqCst), 0);
}

#[test]
fn drops_u8() {
    static CNT: AtomicUsize = AtomicUsize::new(0);
    CNT.store(0, SeqCst);

    #[derive(Debug, PartialEq, Eq)]
    struct Foo(u8);

    impl Foo {
        fn new(val: u8) -> Foo {
            CNT.fetch_add(1, SeqCst);
            Foo(val)
        }
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            CNT.fetch_sub(1, SeqCst);
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new(0)
        }
    }

    let a = AtomicCell::new(Foo::new(5));

    assert_eq!(a.swap(Foo::new(6)), Foo::new(5));
    assert_eq!(a.swap(Foo::new(1)), Foo::new(6));
    assert_eq!(CNT.load(SeqCst), 1);

    a.store(Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(0));
    assert_eq!(CNT.load(SeqCst), 1);

    drop(a);
    assert_eq!(CNT.load(SeqCst), 0);
}

#[test]
fn drops_usize() {
    static CNT: AtomicUsize = AtomicUsize::new(0);
    CNT.store(0, SeqCst);

    #[derive(Debug, PartialEq, Eq)]
    struct Foo(usize);

    impl Foo {
        fn new(val: usize) -> Foo {
            CNT.fetch_add(1, SeqCst);
            Foo(val)
        }
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            CNT.fetch_sub(1, SeqCst);
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new(0)
        }
    }

    let a = AtomicCell::new(Foo::new(5));

    assert_eq!(a.swap(Foo::new(6)), Foo::new(5));
    assert_eq!(a.swap(Foo::new(1)), Foo::new(6));
    assert_eq!(CNT.load(SeqCst), 1);

    a.store(Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(2));
    assert_eq!(CNT.load(SeqCst), 1);

    assert_eq!(a.swap(Foo::default()), Foo::new(0));
    assert_eq!(CNT.load(SeqCst), 1);

    drop(a);
    assert_eq!(CNT.load(SeqCst), 0);
}

#[test]
fn modular_u8() {
    #[derive(Clone, Copy, Eq, Debug, Default)]
    struct Foo(u8);

    impl PartialEq for Foo {
        fn eq(&self, other: &Foo) -> bool {
            self.0 % 5 == other.0 % 5
        }
    }

    let a = AtomicCell::new(Foo(1));

    assert_eq!(a.load(), Foo(1));
    assert_eq!(a.swap(Foo(2)), Foo(11));
    assert_eq!(a.load(), Foo(52));

    a.store(Foo(0));
    assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100)));
    assert_eq!(a.load().0, 5);
    assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100)));
    assert_eq!(a.load().0, 15);
}

#[test]
fn modular_usize() {
    #[derive(Clone, Copy, Eq, Debug, Default)]
    struct Foo(usize);

    impl PartialEq for Foo {
        fn eq(&self, other: &Foo) -> bool {
            self.0 % 5 == other.0 % 5
        }
    }

    let a = AtomicCell::new(Foo(1));

    assert_eq!(a.load(), Foo(1));
    assert_eq!(a.swap(Foo(2)), Foo(11));
    assert_eq!(a.load(), Foo(52));

    a.store(Foo(0));
    assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100)));
    assert_eq!(a.load().0, 5);
    assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100)));
    assert_eq!(a.load().0, 15);
}

#[test]
fn garbage_padding() {
    #[derive(Copy, Clone, Eq, PartialEq)]
    struct Object {
        a: i64,
        b: i32,
    }

    let cell = AtomicCell::new(Object { a: 0, b: 0 });
    let _garbage = [0xfe, 0xfe, 0xfe, 0xfe, 0xfe]; // Needed
    let next = Object { a: 0, b: 0 };

    let prev = cell.load();
    assert!(cell.compare_exchange(prev, next).is_ok());
    println!();
}

#[test]
fn const_atomic_cell_new() {
    static CELL: AtomicCell<usize> = AtomicCell::new(0);

    CELL.store(1);
    assert_eq!(CELL.load(), 1);
}

// https://github.com/crossbeam-rs/crossbeam/pull/767
macro_rules! test_arithmetic {
    ($test_name:ident, $ty:ident) => {
        #[test]
        fn $test_name() {
            let a: AtomicCell<$ty> = AtomicCell::new(7);

            assert_eq!(a.fetch_add(3), 7);
            assert_eq!(a.load(), 10);

            assert_eq!(a.fetch_sub(3), 10);
            assert_eq!(a.load(), 7);

            assert_eq!(a.fetch_and(3), 7);
            assert_eq!(a.load(), 3);

            assert_eq!(a.fetch_or(16), 3);
            assert_eq!(a.load(), 19);

            assert_eq!(a.fetch_xor(2), 19);
            assert_eq!(a.load(), 17);

            assert_eq!(a.fetch_max(18), 17);
            assert_eq!(a.load(), 18);

            assert_eq!(a.fetch_min(17), 18);
            assert_eq!(a.load(), 17);

            assert_eq!(a.fetch_nand(7), 17);
            assert_eq!(a.load(), !(17 & 7));
        }
    };
}
test_arithmetic!(arithmetic_u8, u8);
test_arithmetic!(arithmetic_i8, i8);
test_arithmetic!(arithmetic_u16, u16);
test_arithmetic!(arithmetic_i16, i16);
test_arithmetic!(arithmetic_u32, u32);
test_arithmetic!(arithmetic_i32, i32);
test_arithmetic!(arithmetic_u64, u64);
test_arithmetic!(arithmetic_i64, i64);
test_arithmetic!(arithmetic_u128, u128);
test_arithmetic!(arithmetic_i128, i128);

// https://github.com/crossbeam-rs/crossbeam/issues/748
#[cfg_attr(miri, ignore)] // TODO
#[rustversion::since(1.37)] // #[repr(align(N))] requires Rust 1.37
#[test]
fn issue_748() {
    #[allow(dead_code)]
    #[repr(align(8))]
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    enum Test {
        Field(u32),
        FieldLess,
    }

    assert_eq!(mem::size_of::<Test>(), 8);
    assert_eq!(
        AtomicCell::<Test>::is_lock_free(),
        cfg!(not(crossbeam_no_atomic_64))
    );
    let x = AtomicCell::new(Test::FieldLess);
    assert_eq!(x.load(), Test::FieldLess);
}

// https://github.com/crossbeam-rs/crossbeam/issues/833
#[rustversion::since(1.40)] // const_constructor requires Rust 1.40
#[test]
fn issue_833() {
    use std::num::NonZeroU128;
    use std::thread;

    const N: usize = 1_000_000;

    #[allow(dead_code)]
    enum Enum {
        NeverConstructed,
        Cell(AtomicCell<NonZeroU128>),
    }

    static STATIC: Enum = Enum::Cell(AtomicCell::new(match NonZeroU128::new(1) {
        Some(nonzero) => nonzero,
        None => unreachable!(),
    }));

    thread::spawn(|| {
        let cell = match &STATIC {
            Enum::NeverConstructed => unreachable!(),
            Enum::Cell(cell) => cell,
        };
        let x = NonZeroU128::new(0xFFFF_FFFF_FFFF_FFFF_0000_0000_0000_0000).unwrap();
        let y = NonZeroU128::new(0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFF).unwrap();
        loop {
            cell.store(x);
            cell.store(y);
        }
    });

    for _ in 0..N {
        if let Enum::NeverConstructed = STATIC {
            unreachable!(":(");
        }
    }
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::error;
use std::fmt;

use event::{Event, React};
use render::MetaRenderer;
use super::context::{RenderContextView, State, UpdateContextView};

pub enum Transition<T, R>
    where T: State,
          R: MetaRenderer
{
    None,
    Push(BoxActivity<T, R>),
    Pop,
    Abort,
}

impl<T, R> Transition<T, R>
    where T: State,
          R: MetaRenderer
{
    fn is_abort(&self) -> bool {
        match *self {
            Transition::Abort => true,
            _ => false,
        }
    }
}

pub type BoxActivity<T, R> = Box<Activity<T, R>>;
pub type UpdateResult<T, R> = Result<Transition<T, R>, ActivityError>;
pub type RenderResult = Result<(), ActivityError>;

pub trait Activity<T, R>: React
    where T: State,
          R: MetaRenderer
{
    // TODO: It could be useful to extract `update` and `render` into generic
    //       traits of their own, but this would require associated types and
    //       there is currently no good way to bind those (until trait aliases
    //       land). Consider refactoring this once that is possible and clean.
    fn update(&mut self, context: &mut UpdateContextView<State = T>) -> UpdateResult<T, R>;
    fn render(&mut self, context: &mut RenderContextView<R, State = T>) -> RenderResult;
    fn pause(&mut self) {}
    fn resume(&mut self) {}
    fn stop(&mut self) {}
}

pub struct ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    stack: Vec<BoxActivity<T, R>>,
}

impl<T, R> ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    pub fn new(activity: BoxActivity<T, R>) -> Self {
        ActivityStack {
            stack: vec![activity],
        }
    }

    pub fn update<C>(&mut self, context: &mut C) -> Result<bool, ActivityStackError>
        where C: UpdateContextView<State = T>
    {
        let transition = self.peek_mut().map_or(
            Ok(Transition::Abort), |activity| activity.update(context))?;
        let signal = !transition.is_abort();
        match transition {
            Transition::Push(activity) => { self.push(activity); }
            Transition::Pop => { self.pop(); }
            Transition::Abort => { self.abort(); }
            _ => {}
        }
        Ok(signal)
    }

    pub fn render<C>(&mut self, context: &mut C) -> Result<(), ActivityStackError>
        where C: RenderContextView<R, State = T>
    {
        self.peek_mut().map_or(Ok(()), |activity| {
            activity.render(context).map_err(|error| error.into())
        })
    }

    fn peek_mut(&mut self) -> Option<&mut Activity<T, R>> {
        if let Some(activity) = self.stack.last_mut() { // Cannot use `map`.
            Some(activity.as_mut())
        }
        else {
            None
        }
    }

    fn push(&mut self, activity: BoxActivity<T, R>) {
        if let Some(activity) = self.peek_mut() {
            activity.pause();
        }
        self.stack.push(activity);
    }

    fn pop(&mut self) -> bool {
        self.stack.pop().map(|mut activity| {
            activity.stop();
            if let Some(activity) = self.peek_mut() {
                activity.resume()
            }
        }).is_some()
    }

    fn abort(&mut self) {
        while self.pop() {}
    }
}

impl<T, R> Drop for ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    fn drop(&mut self) {
        self.abort();
    }
}

impl<T, R> React for ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    fn react(&mut self, event: &Event) {
        if let Some(activity) = self.peek_mut() {
            activity.react(event);
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct ActivityError;

impl fmt::Display for ActivityError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;

        write!(formatter, "{}", self.description())
    }
}

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

#[derive(Clone, Copy, Debug)]
pub struct ActivityStackError;

impl fmt::Display for ActivityStackError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;

        write!(formatter, "{}", self.description())
    }
}

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

impl From<ActivityError> for ActivityStackError {
    fn from(_: ActivityError) -> Self {
        ActivityStackError
    }
}
<commit_msg>Rename `pause` to `suspend`.<commit_after>use std::convert::From;
use std::error;
use std::fmt;

use event::{Event, React};
use render::MetaRenderer;
use super::context::{RenderContextView, State, UpdateContextView};

pub enum Transition<T, R>
    where T: State,
          R: MetaRenderer
{
    None,
    Push(BoxActivity<T, R>),
    Pop,
    Abort,
}

impl<T, R> Transition<T, R>
    where T: State,
          R: MetaRenderer
{
    fn is_abort(&self) -> bool {
        match *self {
            Transition::Abort => true,
            _ => false,
        }
    }
}

pub type BoxActivity<T, R> = Box<Activity<T, R>>;
pub type UpdateResult<T, R> = Result<Transition<T, R>, ActivityError>;
pub type RenderResult = Result<(), ActivityError>;

pub trait Activity<T, R>: React
    where T: State,
          R: MetaRenderer
{
    // TODO: It could be useful to extract `update` and `render` into generic
    //       traits of their own, but this would require associated types and
    //       there is currently no good way to bind those (until trait aliases
    //       land). Consider refactoring this once that is possible and clean.
    fn update(&mut self, context: &mut UpdateContextView<State = T>) -> UpdateResult<T, R>;
    fn render(&mut self, context: &mut RenderContextView<R, State = T>) -> RenderResult;
    fn suspend(&mut self) {}
    fn resume(&mut self) {}
    fn stop(&mut self) {}
}

pub struct ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    stack: Vec<BoxActivity<T, R>>,
}

impl<T, R> ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    pub fn new(activity: BoxActivity<T, R>) -> Self {
        ActivityStack {
            stack: vec![activity],
        }
    }

    pub fn update<C>(&mut self, context: &mut C) -> Result<bool, ActivityStackError>
        where C: UpdateContextView<State = T>
    {
        let transition = self.peek_mut().map_or(
            Ok(Transition::Abort), |activity| activity.update(context))?;
        let signal = !transition.is_abort();
        match transition {
            Transition::Push(activity) => { self.push(activity); }
            Transition::Pop => { self.pop(); }
            Transition::Abort => { self.abort(); }
            _ => {}
        }
        Ok(signal)
    }

    pub fn render<C>(&mut self, context: &mut C) -> Result<(), ActivityStackError>
        where C: RenderContextView<R, State = T>
    {
        self.peek_mut().map_or(Ok(()), |activity| {
            activity.render(context).map_err(|error| error.into())
        })
    }

    fn peek_mut(&mut self) -> Option<&mut Activity<T, R>> {
        if let Some(activity) = self.stack.last_mut() { // Cannot use `map`.
            Some(activity.as_mut())
        }
        else {
            None
        }
    }

    fn push(&mut self, activity: BoxActivity<T, R>) {
        if let Some(activity) = self.peek_mut() {
            activity.suspend();
        }
        self.stack.push(activity);
    }

    fn pop(&mut self) -> bool {
        self.stack.pop().map(|mut activity| {
            activity.stop();
            if let Some(activity) = self.peek_mut() {
                activity.resume()
            }
        }).is_some()
    }

    fn abort(&mut self) {
        while self.pop() {}
    }
}

impl<T, R> Drop for ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    fn drop(&mut self) {
        self.abort();
    }
}

impl<T, R> React for ActivityStack<T, R>
    where T: State,
          R: MetaRenderer
{
    fn react(&mut self, event: &Event) {
        if let Some(activity) = self.peek_mut() {
            activity.react(event);
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct ActivityError;

impl fmt::Display for ActivityError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;

        write!(formatter, "{}", self.description())
    }
}

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

#[derive(Clone, Copy, Debug)]
pub struct ActivityStackError;

impl fmt::Display for ActivityStackError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;

        write!(formatter, "{}", self.description())
    }
}

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

impl From<ActivityError> for ActivityStackError {
    fn from(_: ActivityError) -> Self {
        ActivityStackError
    }
}
<|endoftext|>


<commit_before>use std;
use std::cmp::Ordering;
use std::collections::BinaryHeap;

/// Evaluates minimal path cost for each vertex u from `start`.
/// g[u][_] = (u, v, w): an edge from u to v with cost w.
/// dist[v] = cost of minimal-cost path from `start` to `v`.
pub fn dijkstra(g: &Vec<Vec<(usize, usize, i64)>>, start: usize) -> Vec<i64> {
    #[derive(PartialEq, Eq, Ord, Clone, Debug)]
    struct Route {
        cost: i64,
        vertex: usize,
    };

    impl PartialOrd for Route {
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
            other.cost.partial_cmp(&self.cost)
        }
    }

    let n = g.len();
    let mut dist = vec![std::i64::MAX; n];
    dist[start] = 0;

    let mut heap = BinaryHeap::new();
    heap.push(Route {
        cost: 0,
        vertex: start,
    });

    while let Some(Route { cost: d, vertex: u }) = heap.pop() {
        for &(_, v, cost) in g[u].iter() {
            let d = d + cost;

            if d < dist[v] {
                dist[v] = d;
                heap.push(Route { cost: d, vertex: v });
            }
        }
    }

    dist
}

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

    #[test]
    fn test() {
        //       1
        //   [0] --> [1]*
        //      \     |
        //     3  \   | 5
        //          \ |
        //   [2] --> [3]
        //       7

        let n = 4;
        let edges = vec![(0, 1, 1), (0, 3, 3), (1, 3, 5), (2, 3, 7)];
        let mut g = vec![vec![]; n];
        for (u, v, w) in edges {
            g[u].push((u, v, w));
            g[v].push((v, u, w));
        }

        let dist = dijkstra(&g, 1);
        assert_eq!(dist, vec![1, 0, 1 + 3 + 7, 1 + 3]);
    }
}
<commit_msg>feat: dijkstra に枝刈りを追加<commit_after>use std;
use std::cmp::Ordering;
use std::collections::BinaryHeap;

/// Evaluates minimal path cost for each vertex u from `start`.
/// g[u][_] = (u, v, w): an edge from u to v with cost w.
/// dist[v] = cost of minimal-cost path from `start` to `v`.
pub fn dijkstra(g: &Vec<Vec<(usize, usize, i64)>>, start: usize) -> Vec<i64> {
    #[derive(PartialEq, Eq, Ord, Clone, Debug)]
    struct Route {
        cost: i64,
        vertex: usize,
    };

    impl PartialOrd for Route {
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
            other.cost.partial_cmp(&self.cost)
        }
    }

    let n = g.len();
    let mut dist = vec![std::i64::MAX; n];
    dist[start] = 0;

    let mut heap = BinaryHeap::new();
    heap.push(Route {
        cost: 0,
        vertex: start,
    });

    while let Some(Route { cost: d, vertex: u }) = heap.pop() {
        if d > dist[u] {
            continue;
        }

        for &(_, v, cost) in g[u].iter() {
            let d = d + cost;

            if d < dist[v] {
                dist[v] = d;
                heap.push(Route { cost: d, vertex: v });
            }
        }
    }

    dist
}

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

    #[test]
    fn test() {
        //       1
        //   [0] --> [1]*
        //      \     |
        //     3  \   | 5
        //          \ |
        //   [2] --> [3]
        //       7

        let n = 4;
        let edges = vec![(0, 1, 1), (0, 3, 3), (1, 3, 5), (2, 3, 7)];
        let mut g = vec![vec![]; n];
        for (u, v, w) in edges {
            g[u].push((u, v, w));
            g[v].push((v, u, w));
        }

        let dist = dijkstra(&g, 1);
        assert_eq!(dist, vec![1, 0, 1 + 3 + 7, 1 + 3]);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use crate::vector3d::Vector3D;

struct Direction {
    name: &'static str,
    opposite: &'static str,
    abbreviation: &'static str,
    vector: Vector3D,
}

impl Direction {
    const fn new(
        name: &'static str,
        opposite: &'static str,
        abbreviation: &'static str,
        vector: Vector3D,
    ) -> Self {
        Self {
            name,
            opposite,
            abbreviation,
            vector,
        }
    }
}

const DIRECTIONS: [Direction; 10] = [
    Direction::new("north", "south", "n", Vector3D::new(0, -1, 0)),
    Direction::new("northeast", "southwest", "ne", Vector3D::new(1, -1, 0)),
    Direction::new("east", "west", "e", Vector3D::new(1, 0, 0)),
    Direction::new("southeast", "northwest", "se", Vector3D::new(1, 1, 0)),
    Direction::new("south", "north", "s", Vector3D::new(0, 1, 0)),
    Direction::new("southwest", "northeast", "sw", Vector3D::new(-1, 1, 0)),
    Direction::new("west", "east", "w", Vector3D::new(-1, 0, 0)),
    Direction::new("northwest", "southeast", "nw", Vector3D::new(-1, -1, 0)),
    Direction::new("up", "down", "u", Vector3D::new(0, 0, 1)),
    Direction::new("down", "up", "d", Vector3D::new(0, 0, -1)),
];

pub fn compare_exit_names(name1: &&str, name2: &&str) -> Ordering {
    if let Some(index1) = index_of_direction(name1) {
        if let Some(index2) = index_of_direction(name2) {
            index1.cmp(&index2)
        } else {
            Ordering::Less
        }
    } else if is_direction(name2) {
        Ordering::Greater
    } else {
        name1.to_lowercase().cmp(&name2.to_lowercase())
    }
}

pub fn direction_by_abbreviation(string: &str) -> Option<&'static str> {
    index_of_direction_abbreviation(string).map(|index| DIRECTIONS[index].name)
}

fn index_of_direction(direction: &str) -> Option<usize> {
    for i in 0..DIRECTIONS.len() {
        if DIRECTIONS[i].name == direction {
            return Some(i);
        }
    }
    None
}

fn index_of_direction_abbreviation(direction_abbreviation: &str) -> Option<usize> {
    for i in 0..DIRECTIONS.len() {
        if DIRECTIONS[i].abbreviation == direction_abbreviation {
            return Some(i);
        }
    }
    None
}

pub fn is_direction(string: &str) -> bool {
    index_of_direction(string).is_some()
}

pub fn is_direction_abbreviation(string: &str) -> bool {
    index_of_direction_abbreviation(string).is_some()
}

pub fn vector_for_direction(direction: &str) -> Vector3D {
    if let Some(index) = index_of_direction(direction) {
        DIRECTIONS[index].vector.clone()
    } else {
        Vector3D::default()
    }
}
<commit_msg>Minor tweaks<commit_after>use std::cmp::Ordering;

use crate::vector3d::Vector3D;

struct Direction {
    name: &'static str,
    opposite: &'static str,
    abbreviation: &'static str,
    vector: Vector3D,
}

impl Direction {
    const fn new(
        name: &'static str,
        opposite: &'static str,
        abbreviation: &'static str,
        vector: Vector3D,
    ) -> Self {
        Self {
            name,
            opposite,
            abbreviation,
            vector,
        }
    }
}

const DIRECTIONS: [Direction; 10] = [
    Direction::new("north", "south", "n", Vector3D::new(0, -1, 0)),
    Direction::new("northeast", "southwest", "ne", Vector3D::new(1, -1, 0)),
    Direction::new("east", "west", "e", Vector3D::new(1, 0, 0)),
    Direction::new("southeast", "northwest", "se", Vector3D::new(1, 1, 0)),
    Direction::new("south", "north", "s", Vector3D::new(0, 1, 0)),
    Direction::new("southwest", "northeast", "sw", Vector3D::new(-1, 1, 0)),
    Direction::new("west", "east", "w", Vector3D::new(-1, 0, 0)),
    Direction::new("northwest", "southeast", "nw", Vector3D::new(-1, -1, 0)),
    Direction::new("up", "down", "u", Vector3D::new(0, 0, 1)),
    Direction::new("down", "up", "d", Vector3D::new(0, 0, -1)),
];

pub fn compare_exit_names(name1: &&str, name2: &&str) -> Ordering {
    if let Some(index1) = index_of_direction(name1) {
        if let Some(index2) = index_of_direction(name2) {
            index1.cmp(&index2)
        } else {
            Ordering::Less
        }
    } else if is_direction(name2) {
        Ordering::Greater
    } else {
        name1.to_lowercase().cmp(&name2.to_lowercase())
    }
}

pub fn direction_by_abbreviation(string: &str) -> Option<&'static str> {
    index_of_direction_abbreviation(string).map(|index| DIRECTIONS[index].name)
}

fn index_of_direction(direction_str: &str) -> Option<usize> {
    for (i, direction) in DIRECTIONS.iter().enumerate() {
        if direction.name == direction_str {
            return Some(i);
        }
    }
    None
}

fn index_of_direction_abbreviation(direction_abbreviation: &str) -> Option<usize> {
    for (i, direction) in DIRECTIONS.iter().enumerate() {
        if direction.abbreviation == direction_abbreviation {
            return Some(i);
        }
    }
    None
}

pub fn is_direction(string: &str) -> bool {
    index_of_direction(string).is_some()
}

pub fn is_direction_abbreviation(string: &str) -> bool {
    index_of_direction_abbreviation(string).is_some()
}

pub fn vector_for_direction(direction: &str) -> Vector3D {
    if let Some(index) = index_of_direction(direction) {
        DIRECTIONS[index].vector.clone()
    } else {
        Vector3D::default()
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// This program exercises the Rust GIF decoder at
// https://github.com/image-rs/image-gif
// which is the top result for https://crates.io/search?q=gif&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust GIF implementations. The equivalent Wuffs
// benchmarks (on the same test images) are run via:
//
// wuffs bench std/gif
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

// TODO: unify this program, bench-rust-gif-dot-rs, with bench-rust-gif, the
// other Rust GIF benchmark program. They are two separate programs because
// both libraries want to be named "gif", and the cargo package manager cannot
// handle duplicate names (https://github.com/rust-lang/cargo/issues/1311).

extern crate gif;
extern crate rustc_version_runtime;

use gif::SetParameter;
use std::time::Instant;

const ITERSCALE: u64 = 10;
const REPS: u64 = 5;

fn main() {
    let version = rustc_version_runtime::version();
    print!(
        "# Rust {}.{}.{}\n",
        version.major,
        version.minor,
        version.patch
    );
    print!("#\n");
    print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
    print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
    print!("# install Go, then run \"go get golang.org/x/perf/cmd/benchstat\".\n");

    let mut dst = vec![0u8; 64 * 1024 * 1024];

    for _ in 0..REPS {
        bench(
            "1k_bw",
            &mut dst[..],
            include_bytes!("../../../test/data/pjw-thumbnail.gif"),
            2000, // iters_unscaled
        );

        bench(
            "1k_color",
            &mut dst[..],
            include_bytes!("../../../test/data/hippopotamus.regular.gif"),
            1000, // iters_unscaled
        );

        bench(
            "10k_bgra",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            100, // iters_unscaled
        );

        bench(
            "10k_indexed",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            100, // iters_unscaled
        );

        bench(
            "20k",
            &mut dst[..],
            include_bytes!("../../../test/data/bricks-gray.gif"),
            50, // iters_unscaled
        );

        bench(
            "100k_artificial",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.primitive.gif"),
            15, // iters_unscaled
        );

        bench(
            "100k_realistic",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.regular.gif"),
            10, // iters_unscaled
        );

        bench(
            "1000k",
            &mut dst[..],
            include_bytes!("../../../test/data/harvesters.gif"),
            1, // iters_unscaled
        );

        bench(
            "anim_screencap",
            &mut dst[..],
            include_bytes!("../../../test/data/gifplayer-muybridge.gif"),
            1, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let output_32_bit_color = name.ends_with("_bgra");
    let mut num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        num_bytes += decode(&mut dst[..], src, output_32_bit_color);
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = num_bytes * 1_000_000 / elapsed_nanos;
    print!(
        "Benchmarkrust_gif_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8], output_32_bit_color: bool) -> u64 {
    let mut decoder = gif::Decoder::new(src);
    if output_32_bit_color {
        decoder.set(gif::ColorOutput::RGBA);
    }

    let mut num_bytes = 0u64;
    let mut reader = decoder.read_info().unwrap();
    while let Some(_) = reader.next_frame_info().unwrap() {
        num_bytes += reader.buffer_size() as u64;
        reader.read_into_buffer(dst).unwrap();
    }
    num_bytes
}
<commit_msg>Add a warm-up rep to script/bench-rust-gif<commit_after>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// This program exercises the Rust GIF decoder at
// https://github.com/image-rs/image-gif
// which is the top result for https://crates.io/search?q=gif&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust GIF implementations. The equivalent Wuffs
// benchmarks (on the same test images) are run via:
//
// wuffs bench std/gif
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

// TODO: unify this program, bench-rust-gif-dot-rs, with bench-rust-gif, the
// other Rust GIF benchmark program. They are two separate programs because
// both libraries want to be named "gif", and the cargo package manager cannot
// handle duplicate names (https://github.com/rust-lang/cargo/issues/1311).

extern crate gif;
extern crate rustc_version_runtime;

use gif::SetParameter;
use std::time::Instant;

const ITERSCALE: u64 = 10;
const REPS: u64 = 5;

fn main() {
    let version = rustc_version_runtime::version();
    print!(
        "# Rust {}.{}.{}\n",
        version.major,
        version.minor,
        version.patch
    );
    print!("#\n");
    print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
    print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
    print!("# install Go, then run \"go get golang.org/x/perf/cmd/benchstat\".\n");

    let mut dst = vec![0u8; 64 * 1024 * 1024];

    // The various magic constants below are copied from test/c/std/gif.c
    for i in 0..(1 + REPS) {
        bench(
            "1k_bw",
            &mut dst[..],
            include_bytes!("../../../test/data/pjw-thumbnail.gif"),
            i == 0, // warm_up
            2000, // iters_unscaled
        );

        bench(
            "1k_color",
            &mut dst[..],
            include_bytes!("../../../test/data/hippopotamus.regular.gif"),
            i == 0, // warm_up
            1000, // iters_unscaled
        );

        bench(
            "10k_bgra",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            i == 0, // warm_up
            100, // iters_unscaled
        );

        bench(
            "10k_indexed",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            i == 0, // warm_up
            100, // iters_unscaled
        );

        bench(
            "20k",
            &mut dst[..],
            include_bytes!("../../../test/data/bricks-gray.gif"),
            i == 0, // warm_up
            50, // iters_unscaled
        );

        bench(
            "100k_artificial",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.primitive.gif"),
            i == 0, // warm_up
            15, // iters_unscaled
        );

        bench(
            "100k_realistic",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.regular.gif"),
            i == 0, // warm_up
            10, // iters_unscaled
        );

        bench(
            "1000k",
            &mut dst[..],
            include_bytes!("../../../test/data/harvesters.gif"),
            i == 0, // warm_up
            1, // iters_unscaled
        );

        bench(
            "anim_screencap",
            &mut dst[..],
            include_bytes!("../../../test/data/gifplayer-muybridge.gif"),
            i == 0, // warm_up
            1, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    warm_up: bool, // Whether this is a warm up rep.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let output_32_bit_color = name.ends_with("_bgra");
    let mut num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        num_bytes += decode(&mut dst[..], src, output_32_bit_color);
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = num_bytes * 1_000_000 / elapsed_nanos;

    if warm_up {
        return;
    }

    print!(
        "Benchmarkrust_gif_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8], output_32_bit_color: bool) -> u64 {
    let mut decoder = gif::Decoder::new(src);
    if output_32_bit_color {
        decoder.set(gif::ColorOutput::RGBA);
    }

    let mut num_bytes = 0u64;
    let mut reader = decoder.read_info().unwrap();
    while let Some(_) = reader.next_frame_info().unwrap() {
        num_bytes += reader.buffer_size() as u64;
        reader.read_into_buffer(dst).unwrap();
    }
    num_bytes
}
<|endoftext|>


<commit_before>bitflags! {
    struct DisplayControlFlags: u8 {
        const DISPLAY_CONTROL       = 0b0000_1000;
        const DISPLAY_ON            = 0b0000_0100;
        const CURSOR_ON             = 0b0000_0010;
        const CURSOR_BLINKING_ON    = 0b0000_0001;
        const DISPLAY_OFF           = 0b0000_0000;
        const CURSOR_OFF            = 0b0000_0000;
        const CURSOR_BLINKING_OFF   = 0b0000_0000;
    }
}

/// State of a display.
#[derive(Clone, Copy)]
pub enum DisplayState {
    On,
    Off,
}

impl From<DisplayState> for DisplayControlFlags {
    fn from(state: DisplayState) -> Self {
        match state {
            DisplayState::On => DISPLAY_ON,
            DisplayState::Off => DISPLAY_OFF,
        }
    }
}

/// State of a cursor.
#[derive(Clone, Copy)]
pub enum CursorState {
    On,
    Off,
}

impl From<CursorState> for DisplayControlFlags {
    fn from(state: CursorState) -> Self {
        match state {
            CursorState::On => CURSOR_ON,
            CursorState::Off => CURSOR_OFF,
        }
    }
}

/// Sets cursor blinking.
#[derive(Clone, Copy)]
pub enum CursorBlinking {
    On,
    Off,
}

impl From<CursorBlinking> for DisplayControlFlags {
    fn from(state: CursorBlinking) -> Self {
        match state {
            CursorBlinking::On => CURSOR_BLINKING_ON,
            CursorBlinking::Off => CURSOR_BLINKING_OFF,
        }
    }
}

/// A struct for creating display control settings.
pub struct DisplayControlBuilder {
    display: DisplayState,
    cursor: CursorState,
    blinking: CursorBlinking,
}

impl DisplayControlBuilder {
    /// Sets the entire display `On` or `Off`.
    ///
    /// Default is `On`.
    pub fn set_display(&mut self, state: DisplayState) -> &mut Self {
        self.display = state;
        self
    }

    /// Sets the cursor `On` or `Off`.
    ///
    /// Default is `Off`.
    ///
    /// **Note:** This will not change cursor move direction or any other settings.
    pub fn set_cursor(&mut self, state: CursorState) -> &mut Self {
        self.cursor = state;
        self
    }

    /// Sets the blinking of the cursor `On` of `Off`.
    ///
    /// Default is `Off`.
    pub fn set_cursor_blinking(&mut self, blinking: CursorBlinking) -> &mut Self {
        self.blinking = blinking;
        self
    }

    pub(crate) fn build_command(&self) -> u8 {
        let mut cmd = DISPLAY_CONTROL;

        cmd |= DisplayControlFlags::from(self.display);
        cmd |= DisplayControlFlags::from(self.cursor);
        cmd |= DisplayControlFlags::from(self.blinking);

        cmd.bits()
    }
}

impl Default for DisplayControlBuilder {
    /// Makes a new `DisplayControlBuilder` using the default settings described below.
    ///
    /// The default settings are:
    ///
    ///  - **display:**
    ///     - `On`
    ///  - **cursor:**
    ///     - `Off`
    ///  - **blinkinging of cursor:**
    ///     - `Off`
    fn default() -> Self {
        Self {
            display: DisplayState::On,
            cursor: CursorState::Off,
            blinking: CursorBlinking::Off,
        }
    }
}
<commit_msg>Add unit tests to display control builder<commit_after>bitflags! {
    struct DisplayControlFlags: u8 {
        const DISPLAY_CONTROL       = 0b0000_1000;
        const DISPLAY_ON            = 0b0000_0100;
        const CURSOR_ON             = 0b0000_0010;
        const CURSOR_BLINKING_ON    = 0b0000_0001;
        const DISPLAY_OFF           = 0b0000_0000;
        const CURSOR_OFF            = 0b0000_0000;
        const CURSOR_BLINKING_OFF   = 0b0000_0000;
    }
}

/// State of a display.
#[derive(Clone, Copy)]
pub enum DisplayState {
    On,
    Off,
}

impl From<DisplayState> for DisplayControlFlags {
    fn from(state: DisplayState) -> Self {
        match state {
            DisplayState::On => DISPLAY_ON,
            DisplayState::Off => DISPLAY_OFF,
        }
    }
}

/// State of a cursor.
#[derive(Clone, Copy)]
pub enum CursorState {
    On,
    Off,
}

impl From<CursorState> for DisplayControlFlags {
    fn from(state: CursorState) -> Self {
        match state {
            CursorState::On => CURSOR_ON,
            CursorState::Off => CURSOR_OFF,
        }
    }
}

/// Sets cursor blinking.
#[derive(Clone, Copy)]
pub enum CursorBlinking {
    On,
    Off,
}

impl From<CursorBlinking> for DisplayControlFlags {
    fn from(state: CursorBlinking) -> Self {
        match state {
            CursorBlinking::On => CURSOR_BLINKING_ON,
            CursorBlinking::Off => CURSOR_BLINKING_OFF,
        }
    }
}

/// A struct for creating display control settings.
pub struct DisplayControlBuilder {
    display: DisplayState,
    cursor: CursorState,
    blinking: CursorBlinking,
}

impl DisplayControlBuilder {
    /// Sets the entire display `On` or `Off`.
    ///
    /// Default is `On`.
    pub fn set_display(&mut self, state: DisplayState) -> &mut Self {
        self.display = state;
        self
    }

    /// Sets the cursor `On` or `Off`.
    ///
    /// Default is `Off`.
    ///
    /// **Note:** This will not change cursor move direction or any other settings.
    pub fn set_cursor(&mut self, state: CursorState) -> &mut Self {
        self.cursor = state;
        self
    }

    /// Sets the blinking of the cursor `On` of `Off`.
    ///
    /// Default is `Off`.
    pub fn set_cursor_blinking(&mut self, blinking: CursorBlinking) -> &mut Self {
        self.blinking = blinking;
        self
    }

    pub(crate) fn build_command(&self) -> u8 {
        let mut cmd = DISPLAY_CONTROL;

        cmd |= DisplayControlFlags::from(self.display);
        cmd |= DisplayControlFlags::from(self.cursor);
        cmd |= DisplayControlFlags::from(self.blinking);

        cmd.bits()
    }
}

impl Default for DisplayControlBuilder {
    /// Makes a new `DisplayControlBuilder` using the default settings described below.
    ///
    /// The default settings are:
    ///
    ///  - **display:**
    ///     - `On`
    ///  - **cursor:**
    ///     - `Off`
    ///  - **blinkinging of cursor:**
    ///     - `Off`
    fn default() -> Self {
        Self {
            display: DisplayState::On,
            cursor: CursorState::Off,
            blinking: CursorBlinking::Off,
        }
    }
}

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

    const DISPLAY_CONTROL_FLAG: u8 = 0b0000_1000;
    const DISPLAY_STATE_FLAG: u8   = 0b0000_0100;
    const CURSOR_STATE_FLAG: u8    = 0b0000_0010;
    const CURSOR_BLINKING_FLAG: u8 = 0b0000_0001;

    fn has_bit(value: u8, bitmask: u8) -> bool {
        value & bitmask == bitmask
    }

    #[test]
    fn display_control_flag() {
        let b = DisplayControlBuilder::default();
        let cmd = b.build_command();

        assert!( has_bit(cmd, DISPLAY_CONTROL_FLAG) );
    }

    #[test]
    fn default_display_state(){
        let b = DisplayControlBuilder::default();
        let cmd = b.build_command();

        assert!( has_bit(cmd, DISPLAY_STATE_FLAG) );
    }

    #[test]
    fn set_display() {
        let mut b = DisplayControlBuilder::default();

        b.set_display(DisplayState::On);
        let cmd = b.build_command();
        assert!( has_bit(cmd, DISPLAY_STATE_FLAG) );

        b.set_display(DisplayState::Off);
        let cmd = b.build_command();
        assert_eq!( has_bit(cmd, DISPLAY_STATE_FLAG), false);
    }

    #[test]
    fn default_cursor_state(){
        let b = DisplayControlBuilder::default();
        let cmd = b.build_command();

        assert_eq!( has_bit(cmd, CURSOR_STATE_FLAG), false );
    }

    #[test]
    fn set_cursor() {
        let mut b = DisplayControlBuilder::default();

        b.set_cursor(CursorState::On);
        let cmd = b.build_command();
        assert!( has_bit(cmd, CURSOR_STATE_FLAG) );

        b.set_cursor(CursorState::Off);
        let cmd = b.build_command();
        assert_eq!( has_bit(cmd, CURSOR_STATE_FLAG), false);
    }

    #[test]
    fn default_cursor_blinking(){
        let b = DisplayControlBuilder::default();
        let cmd = b.build_command();

        assert_eq!( has_bit(cmd, CURSOR_BLINKING_FLAG), false );
    }

    #[test]
    fn set_cursor_blinking() {
        let mut b = DisplayControlBuilder::default();

        b.set_cursor_blinking(CursorBlinking::On);
        let cmd = b.build_command();
        assert!( has_bit(cmd, CURSOR_BLINKING_FLAG) );

        b.set_cursor_blinking(CursorBlinking::Off);
        let cmd = b.build_command();
        assert_eq!( has_bit(cmd, CURSOR_STATE_FLAG), false);
    }
}
<|endoftext|>


<commit_before>use definitions::ImageBuilder;
use definitions::error::*;
use definitions::typedef::*;
use mnemonic::Mnemonic;
use regex::Regex;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

lazy_static! {
    static ref LABELED_MNEMONIC_RE: Regex = Regex::new(r"^\.(.+?) +?(.+)$").unwrap();
    static ref LABEL_RE: Regex = Regex::new(r"^\.([^\s]+)$").unwrap();
    static ref INCLUDE_RE: Regex = Regex::new(r"^include! +([^\s]+)$").unwrap();
}

#[derive(Default)]
struct BASMCompiler {
    label_addr_map: HashMap<String, Address>,
    mnemonics: Vec<Mnemonic>,
    builder: ImageBuilder,
    last_base_dir: Option<PathBuf>,
}

impl BASMCompiler {
    fn add_label(&mut self, label: String) {
        self.label_addr_map.entry(label).or_insert(self.mnemonics.len());
    }

    fn compile_mnemonics(&mut self, file_name: String) -> Result<()> {
        let orig_path = Path::new(&file_name);

        let path = if orig_path.is_relative() {
            let file_name = if let Some(ref file_name) = orig_path.file_name() {
                if let Some(..) = self.last_base_dir {
                    PathBuf::from(orig_path)
                } else {
                    PathBuf::from(file_name.clone())
                }
            } else {
                bail!("unable to obtain file name");
            };

            let absolute_path = if let Some(ref base_dir) = self.last_base_dir {
                base_dir.clone()
            } else {
                let current_dir = env::current_dir()
                    .chain_err(|| "unable to get current directory")?;
                let base_file = current_dir.join(orig_path);
                let base_dir = if let Some(ref dir) = base_file.parent() {
                    dir.clone()
                } else {
                    bail!("unable to get parent directory")
                };

                self.last_base_dir = Some(base_dir.to_path_buf().clone());
                base_dir.to_path_buf()
            };

            absolute_path.join(file_name)
        } else {
            orig_path.clone().to_path_buf()
        };

        let file = File::open(path).chain_err(|| "unable to open file")?;

        let reader = BufReader::new(file);

        for line in reader.lines() {
            let line = line.chain_err(|| "unable to read line")?;

            if line.is_empty() {
                continue;
            }

            let mut r_split = line.rsplitn(2, ';');

            if r_split.clone().count() > 1 {
                r_split.next();
            }

            if let Some(first_half) = r_split.next() {
                let first_half = first_half.trim();

                let first_half: String = if LABELED_MNEMONIC_RE.is_match(first_half) {
                    let captures = if let Some(captures) = LABELED_MNEMONIC_RE
                           .captures_iter(first_half)
                           .next() {
                        captures
                    } else {
                        bail!("no label capture found")
                    };

                    let label = captures[1].trim();

                    println!(
                        "Label {:?} found at address {}",
                        label,
                        self.mnemonics.len()
                    );

                    self.add_label(label.to_owned());

                    captures[2].trim().to_owned()
                } else if LABEL_RE.is_match(first_half) {
                    let captures =
                        if let Some(captures) = LABEL_RE.captures_iter(first_half).next() {
                            captures
                        } else {
                            bail!("no label capture found")
                        };

                    let label = captures[1].trim();

                    println!(
                        "Label {:?} found at address {}",
                        label,
                        self.mnemonics.len()
                    );

                    self.add_label(label.to_owned());
                    continue;
                } else if INCLUDE_RE.is_match(first_half) {
                    let captures =
                        if let Some(captures) = INCLUDE_RE.captures_iter(first_half).next() {
                            captures
                        } else {
                            bail!("no include capture found")
                        };

                    self.compile_mnemonics(captures[1].trim().to_owned() + ".basm")?;

                    continue;
                } else {
                    first_half.to_owned()
                };

                let mut first_half_split = first_half.splitn(2, ' ');

                if let Some(opcode) = first_half_split.next() {
                    let opcode = opcode.trim().to_lowercase();

                    let args: Vec<String> = if let Some(args) = first_half_split.next() {
                        args.split(',').map(|arg| arg.trim().to_owned()).collect()
                    } else {
                        Vec::new()
                    };

                    println!("Adding mnemonic {:?} with args: {:?}", opcode, args);

                    self.mnemonics.push(text_to_mnemonic(opcode, args)?);
                } else {
                    bail!("opcode expected. Found {:?}", first_half_split);
                }
            } else {
                bail!("instruction expected. Found {:?}", line.to_string());
            }
        }

        Ok(())
    }

    fn compile_mnemonic(&mut self, mnemonic: Mnemonic) -> Result<()> {

        println!("Compiling mnemonic {:?}", mnemonic);

        match mnemonic {
            Mnemonic::Add(dest, src) => self.builder.add(dest, src),
            Mnemonic::Sub(dest, src) => self.builder.sub(dest, src),
            Mnemonic::Div(dest, src) => self.builder.div(dest, src),
            Mnemonic::Mul(dest, src) => self.builder.mul(dest, src),
            Mnemonic::Rem(dest, src) => self.builder.rem(dest, src),

            Mnemonic::Cmp(target_a, target_b) => self.builder.cmp(target_a, target_b),
            Mnemonic::Jmp(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp(addr);
            }
            Mnemonic::JmpLt(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_lt(addr);
            }
            Mnemonic::JmpGt(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_gt(addr);
            }
            Mnemonic::JmpEq(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_eq(addr);
            }
            Mnemonic::JmpLtEq(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_lt_eq(addr);
            }
            Mnemonic::JmpGtEq(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_gt_eq(addr);
            }

            Mnemonic::Cast(target, type_t) => self.builder.cast(target, type_t),

            Mnemonic::Push(target, value) => self.builder.push(target, value),
            Mnemonic::Mov(dest, src) => self.builder.mov(dest, src),
            Mnemonic::Swp(target_a, target_b) => self.builder.swp(target_a, target_b),
            Mnemonic::Dup(target) => self.builder.dup(target),

            Mnemonic::Call(label) => {
                let addr = self.lookup(&label)?;
                self.builder.call(addr);
            }
            Mnemonic::Ret => self.builder.ret(),

            Mnemonic::Halt => self.builder.halt(),
            Mnemonic::Pause => self.builder.pause(),
            Mnemonic::Nop => self.builder.nop(),
            Mnemonic::Int(int) => self.builder.int(int),
        }

        Ok(())
    }

    fn lookup(&mut self, input: &String) -> Result<Address> {
        if let Some(addr) = self.label_addr_map.get(input) {
            Ok(*addr)
        } else {
            bail!("label {:?} not found", input);
        }
    }

    pub fn compile(&mut self, file_name: String) -> Result<ImageData> {
        self.compile_mnemonics(file_name)?;

        for mnemonic in self.mnemonics.clone() {
            self.compile_mnemonic(mnemonic)?;
        }

        Ok(self.builder.clone().gen())
    }
}

fn text_to_mnemonic(opcode: String, args: Vec<String>) -> Result<Mnemonic> {
    match opcode.as_str() {
        "add" => Ok(Mnemonic::Add(args[0].parse()?, args[1].parse()?)),
        "sub" => Ok(Mnemonic::Sub(args[0].parse()?, args[1].parse()?)),
        "div" => Ok(Mnemonic::Div(args[0].parse()?, args[1].parse()?)),
        "mul" => Ok(Mnemonic::Mul(args[0].parse()?, args[1].parse()?)),
        "rem" => Ok(Mnemonic::Rem(args[0].parse()?, args[1].parse()?)),

        "cmp" => Ok(Mnemonic::Cmp(args[0].parse()?, args[1].parse()?)),
        "jmp" => Ok(Mnemonic::Jmp(args[0].parse()?)),
        "jmplt" => Ok(Mnemonic::JmpLt(args[0].parse()?)),
        "jmpgt" => Ok(Mnemonic::JmpGt(args[0].parse()?)),
        "jmpeq" => Ok(Mnemonic::JmpEq(args[0].parse()?)),
        "jmplteq" => Ok(Mnemonic::JmpLtEq(args[0].parse()?)),
        "jmpgteq" => Ok(Mnemonic::JmpGtEq(args[0].parse()?)),

        "cast" => Ok(Mnemonic::Cast(args[0].parse()?, args[1].parse()?)),
        "push" => Ok(Mnemonic::Push(args[0].parse()?, args[1].parse()?)),
        "mov" => Ok(Mnemonic::Mov(args[0].parse()?, args[1].parse()?)),
        "swp" => Ok(Mnemonic::Swp(args[0].parse()?, args[1].parse()?)),
        "dup" => Ok(Mnemonic::Dup(args[0].parse()?)),

        "call" => Ok(Mnemonic::Call(args[0].parse()?)),
        "ret" => Ok(Mnemonic::Ret),

        "halt" => Ok(Mnemonic::Halt),
        "pause" => Ok(Mnemonic::Pause),
        "nop" => Ok(Mnemonic::Nop),
        "int" => Ok(Mnemonic::Int(args[0].parse()?)),
        _ => bail!("unkwnown opcode {:?}", opcode),
    }
}

pub fn compile(file_name: String) -> Result<ImageData> {
    BASMCompiler::default().compile(file_name)
}

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

    #[test]
    fn labeled_mnemonic_regex() {
        let input = ".start mov $st, $vi(19)";

        if !LABELED_MNEMONIC_RE.is_match(input) {
            panic!("input doesn't match a labeled mnemonic");
        } else {
            let captures = LABELED_MNEMONIC_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
            assert_eq!(captures[2].trim(), "mov $st, $vi(19)");
        }
    }

    #[test]
    fn label_regex() {
        let input = ".start";

        if !LABEL_RE.is_match(input) {
            panic!("input doesn't match a label");
        } else {
            let captures = LABEL_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
        }
    }

    #[test]
    fn include_regex() {
        let input = "include! std";

        if !INCLUDE_RE.is_match(input) {
            panic!("input doesn't match an include statement");
        } else {
            let captures = INCLUDE_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "std");
        }
    }
}
<commit_msg>Fixed handling of relative and absolute paths<commit_after>use definitions::ImageBuilder;
use definitions::error::*;
use definitions::typedef::*;
use mnemonic::Mnemonic;
use regex::Regex;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

lazy_static! {
    static ref LABELED_MNEMONIC_RE: Regex = Regex::new(r"^\.(.+?) +?(.+)$").unwrap();
    static ref LABEL_RE: Regex = Regex::new(r"^\.([^\s]+)$").unwrap();
    static ref INCLUDE_RE: Regex = Regex::new(r"^include! +([^\s]+)$").unwrap();
}

#[derive(Default)]
struct BASMCompiler {
    label_addr_map: HashMap<String, Address>,
    mnemonics: Vec<Mnemonic>,
    builder: ImageBuilder,
    last_base_dir: Option<PathBuf>,
}

impl BASMCompiler {
    fn add_label(&mut self, label: String) {
        self.label_addr_map.entry(label).or_insert(self.mnemonics.len());
    }

    fn base_path(&mut self, orig_path: &Path) -> Result<PathBuf> {
        let file_name = if let Some(ref file_name) = orig_path.file_name() {
            if let Some(..) = self.last_base_dir {
                PathBuf::from(orig_path)
            } else {
                PathBuf::from(file_name.clone())
            }
        } else {
            bail!("unable to obtain file name");
        };

        let absolute_path = if let Some(ref base_dir) = self.last_base_dir {
            base_dir.clone()
        } else {
            let current_dir = if orig_path.is_relative() {
                env::current_dir().chain_err(|| "unable to get current directory")?
            } else {
                if let Some(ref parent) = orig_path.parent() {
                    parent.to_path_buf().clone()
                } else {
                    bail!("unable to get parent directory")
                }
            };

            let base_file = current_dir.join(orig_path);
            let base_dir = if let Some(ref dir) = base_file.parent() {
                dir.clone()
            } else {
                bail!("unable to get parent directory")
            };

            self.last_base_dir = Some(base_dir.to_path_buf().clone());
            base_dir.to_path_buf()
        };

        Ok(absolute_path.join(file_name))
    }

    fn compile_mnemonics(&mut self, file_name: String) -> Result<()> {
        let orig_path = Path::new(&file_name);

        let path = self.base_path(orig_path)?;

        let file = File::open(path).chain_err(|| "unable to open file")?;

        let reader = BufReader::new(file);

        for line in reader.lines() {
            let line = line.chain_err(|| "unable to read line")?;

            if line.is_empty() {
                continue;
            }

            let mut r_split = line.rsplitn(2, ';');

            if r_split.clone().count() > 1 {
                r_split.next();
            }

            if let Some(first_half) = r_split.next() {
                let first_half = first_half.trim();

                let first_half: String = if LABELED_MNEMONIC_RE.is_match(first_half) {
                    let captures = if let Some(captures) = LABELED_MNEMONIC_RE
                           .captures_iter(first_half)
                           .next() {
                        captures
                    } else {
                        bail!("no label capture found")
                    };

                    let label = captures[1].trim();

                    println!(
                        "Label {:?} found at address {}",
                        label,
                        self.mnemonics.len()
                    );

                    self.add_label(label.to_owned());

                    captures[2].trim().to_owned()
                } else if LABEL_RE.is_match(first_half) {
                    let captures =
                        if let Some(captures) = LABEL_RE.captures_iter(first_half).next() {
                            captures
                        } else {
                            bail!("no label capture found")
                        };

                    let label = captures[1].trim();

                    println!(
                        "Label {:?} found at address {}",
                        label,
                        self.mnemonics.len()
                    );

                    self.add_label(label.to_owned());
                    continue;
                } else if INCLUDE_RE.is_match(first_half) {
                    let captures =
                        if let Some(captures) = INCLUDE_RE.captures_iter(first_half).next() {
                            captures
                        } else {
                            bail!("no include capture found")
                        };

                    self.compile_mnemonics(captures[1].trim().to_owned() + ".basm")?;

                    continue;
                } else {
                    first_half.to_owned()
                };

                let mut first_half_split = first_half.splitn(2, ' ');

                if let Some(opcode) = first_half_split.next() {
                    let opcode = opcode.trim().to_lowercase();

                    let args: Vec<String> = if let Some(args) = first_half_split.next() {
                        args.split(',').map(|arg| arg.trim().to_owned()).collect()
                    } else {
                        Vec::new()
                    };

                    println!("Adding mnemonic {:?} with args: {:?}", opcode, args);

                    self.mnemonics.push(text_to_mnemonic(opcode, args)?);
                } else {
                    bail!("opcode expected. Found {:?}", first_half_split);
                }
            } else {
                bail!("instruction expected. Found {:?}", line.to_string());
            }
        }

        Ok(())
    }

    fn compile_mnemonic(&mut self, mnemonic: Mnemonic) -> Result<()> {

        println!("Compiling mnemonic {:?}", mnemonic);

        match mnemonic {
            Mnemonic::Add(dest, src) => self.builder.add(dest, src),
            Mnemonic::Sub(dest, src) => self.builder.sub(dest, src),
            Mnemonic::Div(dest, src) => self.builder.div(dest, src),
            Mnemonic::Mul(dest, src) => self.builder.mul(dest, src),
            Mnemonic::Rem(dest, src) => self.builder.rem(dest, src),

            Mnemonic::Cmp(target_a, target_b) => self.builder.cmp(target_a, target_b),
            Mnemonic::Jmp(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp(addr);
            }
            Mnemonic::JmpLt(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_lt(addr);
            }
            Mnemonic::JmpGt(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_gt(addr);
            }
            Mnemonic::JmpEq(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_eq(addr);
            }
            Mnemonic::JmpLtEq(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_lt_eq(addr);
            }
            Mnemonic::JmpGtEq(label) => {
                let addr = self.lookup(&label)?;
                self.builder.jmp_gt_eq(addr);
            }

            Mnemonic::Cast(target, type_t) => self.builder.cast(target, type_t),

            Mnemonic::Push(target, value) => self.builder.push(target, value),
            Mnemonic::Mov(dest, src) => self.builder.mov(dest, src),
            Mnemonic::Swp(target_a, target_b) => self.builder.swp(target_a, target_b),
            Mnemonic::Dup(target) => self.builder.dup(target),

            Mnemonic::Call(label) => {
                let addr = self.lookup(&label)?;
                self.builder.call(addr);
            }
            Mnemonic::Ret => self.builder.ret(),

            Mnemonic::Halt => self.builder.halt(),
            Mnemonic::Pause => self.builder.pause(),
            Mnemonic::Nop => self.builder.nop(),
            Mnemonic::Int(int) => self.builder.int(int),
        }

        Ok(())
    }

    fn lookup(&mut self, input: &String) -> Result<Address> {
        if let Some(addr) = self.label_addr_map.get(input) {
            Ok(*addr)
        } else {
            bail!("label {:?} not found", input);
        }
    }

    pub fn compile(&mut self, file_name: String) -> Result<ImageData> {
        self.compile_mnemonics(file_name)?;

        for mnemonic in self.mnemonics.clone() {
            self.compile_mnemonic(mnemonic)?;
        }

        Ok(self.builder.clone().gen())
    }
}

fn text_to_mnemonic(opcode: String, args: Vec<String>) -> Result<Mnemonic> {
    match opcode.as_str() {
        "add" => Ok(Mnemonic::Add(args[0].parse()?, args[1].parse()?)),
        "sub" => Ok(Mnemonic::Sub(args[0].parse()?, args[1].parse()?)),
        "div" => Ok(Mnemonic::Div(args[0].parse()?, args[1].parse()?)),
        "mul" => Ok(Mnemonic::Mul(args[0].parse()?, args[1].parse()?)),
        "rem" => Ok(Mnemonic::Rem(args[0].parse()?, args[1].parse()?)),

        "cmp" => Ok(Mnemonic::Cmp(args[0].parse()?, args[1].parse()?)),
        "jmp" => Ok(Mnemonic::Jmp(args[0].parse()?)),
        "jmplt" => Ok(Mnemonic::JmpLt(args[0].parse()?)),
        "jmpgt" => Ok(Mnemonic::JmpGt(args[0].parse()?)),
        "jmpeq" => Ok(Mnemonic::JmpEq(args[0].parse()?)),
        "jmplteq" => Ok(Mnemonic::JmpLtEq(args[0].parse()?)),
        "jmpgteq" => Ok(Mnemonic::JmpGtEq(args[0].parse()?)),

        "cast" => Ok(Mnemonic::Cast(args[0].parse()?, args[1].parse()?)),
        "push" => Ok(Mnemonic::Push(args[0].parse()?, args[1].parse()?)),
        "mov" => Ok(Mnemonic::Mov(args[0].parse()?, args[1].parse()?)),
        "swp" => Ok(Mnemonic::Swp(args[0].parse()?, args[1].parse()?)),
        "dup" => Ok(Mnemonic::Dup(args[0].parse()?)),

        "call" => Ok(Mnemonic::Call(args[0].parse()?)),
        "ret" => Ok(Mnemonic::Ret),

        "halt" => Ok(Mnemonic::Halt),
        "pause" => Ok(Mnemonic::Pause),
        "nop" => Ok(Mnemonic::Nop),
        "int" => Ok(Mnemonic::Int(args[0].parse()?)),
        _ => bail!("unkwnown opcode {:?}", opcode),
    }
}

pub fn compile(file_name: String) -> Result<ImageData> {
    BASMCompiler::default().compile(file_name)
}

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

    #[test]
    fn labeled_mnemonic_regex() {
        let input = ".start mov $st, $vi(19)";

        if !LABELED_MNEMONIC_RE.is_match(input) {
            panic!("input doesn't match a labeled mnemonic");
        } else {
            let captures = LABELED_MNEMONIC_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
            assert_eq!(captures[2].trim(), "mov $st, $vi(19)");
        }
    }

    #[test]
    fn label_regex() {
        let input = ".start";

        if !LABEL_RE.is_match(input) {
            panic!("input doesn't match a label");
        } else {
            let captures = LABEL_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
        }
    }

    #[test]
    fn include_regex() {
        let input = "include! std";

        if !INCLUDE_RE.is_match(input) {
            panic!("input doesn't match an include statement");
        } else {
            let captures = INCLUDE_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "std");
        }
    }
}
<|endoftext|>


<commit_before>//! Contains methods for solving eigenvalues, including general and
//! symmetric/Hermitian eigenvalue problems.
//!

pub mod general;
pub mod symmetric;
pub mod types;

pub use self::general::{Eigen};
pub use self::types::{EigenError};
pub use self::symmetric::{SymEigen};
<commit_msg>sample documentation in katex<commit_after>//! Contains methods for solving eigenvalues, including general and
//! symmetric/Hermitian eigenvalue problems.
//!
//! The eigenvalue problem is to find solution $\left(x, \lambda\right)$ to the problem:
//!
//! $$A \cdot x = \lambda \cdot x$$
//!
//! for a square matrix \\(A\\).

pub mod general;
pub mod symmetric;
pub mod types;

pub use self::general::{Eigen};
pub use self::types::{EigenError};
pub use self::symmetric::{SymEigen};
<|endoftext|>


<commit_before>use super::Vector;
use super::Vector3;

pub struct Vector3f {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Vector<f32> for Vector3f {
    fn add(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x += v.x;
        self.y += v.y;
        self.z += v.z;
        self
    }

    fn add_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
        dest.z = self.z + v.z;
    }

    fn angle(&self, v: &Vector3f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector3f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector3f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector3f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        let dz = self.z - v.z;
        (dx * dx) + (dy * dy) + (dz * dz)
    }

    fn dot(&self, v: &Vector3f) -> f32 {
        (self.x * v.x) + (self.y * v.y) + (self.z * v.z)
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector3f) -> &mut Vector3f {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector3f, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector3f, b: &Vector3f) -> &mut Vector3f {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector3f, b: &Vector3f, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        self.length_squared().sqrt()
    }

    fn length_squared(&self) -> f32 {
        (self.x * self.x) + (self.y * self.y) + (self.z * self.z)
    }

    fn lerp(&mut self, other: &Vector3f, t: f32) -> &mut Vector3f {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector3f, t: f32, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Vector3f {
        self.x *= s;
        self.y *= s;
        self.z *= s;
        self
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector3f) {
        dest.x = self.x * s;
        dest.y = self.y * s;
        dest.z = self.z * s;
    }

    fn mul_vector(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x *= v.x;
        self.y *= v.y;
        self.z *= v.z;
        self
    }

    fn mul_vector_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        dest.x = self.x * v.x;
        dest.y = self.y * v.y;
        dest.z = self.z * v.z;
    }

    fn negate(&mut self) -> &mut Vector3f {
        self.x = -self.x;
        self.y = -self.y;
        self.z = -self.z;
        self
    }

    fn negate_into(&self, dest: &mut Vector3f) {
        dest.x = -self.x;
        dest.y = -self.y;
        dest.z = -self.z;
    }

    fn normalize(&mut self) -> &mut Vector3f {
        let inv_length = 1.0f32 / self.length();
        self.x *= inv_length;
        self.y *= inv_length;
        self.z *= inv_length;
        self
    }

    fn normalize_into(&self, dest: &mut Vector3f) {
        let inv_length = 1.0f32 / self.length();
        dest.x = self.x * inv_length;
        dest.y = self.y * inv_length;
        dest.z = self.z * inv_length;
    }

    fn set(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x = v.x;
        self.y = v.y;
        self.z = v.z;
        self
    }

    fn sub(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x -= v.x;
        self.y -= v.y;
        self.z -= v.z;
        self
    }

    fn sub_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        dest.x = self.x - v.x;
        dest.y = self.y - v.y;
        dest.z = self.z - v.z;
    }

    fn zero(&mut self) -> &mut Vector3f {
        self.x = 0f32;
        self.y = 0f32;
        self.z = 0f32;
        self
    }
}

impl Vector3<f32> for Vector3f {
    fn new(x: f32, y: f32, z: f32) -> Vector3f {
        Vector3f {
            x: x,
            y: y,
            z: z,
        }
    }

    fn add_components(&mut self, x: f32, y: f32, z: f32) -> &mut Vector3f {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, z: f32, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn cross(&mut self, v: &Vector3f) -> &mut Vector3f {
        unimplemented!()
    }

    fn cross_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector3;
    use super::Vector3f;

    use std;

    #[test]
    fn test_new() {
        let a = Vector3f::new(1f32, 2f32, 3f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
        assert_eq!(a.z, 3f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        a.add(&b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
        assert_eq!(a.z, 6f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);
        let mut c = Vector3f::new(0f32, 0f32, 0f32);

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 4f32);
        assert_eq!(c.z, 6f32);
    }

    #[test]
    fn test_distance() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(-1f32, 2f32, 3f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(-1f32, 2f32, 3f32);

        let target_distance_sq = 4f32; // target distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }

    #[test]
    fn test_dot() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        let target_dot = 14f32;
        let dot = a.dot(&b);

        assert_eq!(target_dot, dot);
    }

    #[test]
    fn test_length() {
        let a = Vector3f::new(1f32, 2f32, 2f32);

        let target_length = 3f32;
        let length = a.length();

        assert_eq!(target_length, length);
    }

    #[test]
    fn test_length_squared() {
        let a = Vector3f::new(1f32, 2f32, 3f32);

        let target_length_sq = 14f32;
        let length_sq = a.length_squared();

        assert_eq!(target_length_sq, length_sq);
    }

    #[test]
    fn test_mul_scalar() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.mul_scalar(2f32);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
        assert_eq!(a.z, 6f32);
    }

    #[test]
    fn test_mul_scalar_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let mut b = Vector3f::new(0f32, 0f32, 0f32);

        a.mul_scalar_into(2f32, &mut b);

        assert_eq!(b.x, 2f32);
        assert_eq!(b.y, 4f32);
        assert_eq!(b.z, 6f32);
    }

    #[test]
    fn test_mul_vector(){
        let mut a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        a.mul_vector(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 4f32);
        assert_eq!(a.z, 9f32);
    }

    #[test]
    fn test_mul_vector_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);
        let mut c = Vector3f::new(0f32, 0f32, 0f32);

        a.mul_vector_into(&b, &mut c);

        assert_eq!(c.x, 1f32);
        assert_eq!(c.y, 4f32);
        assert_eq!(c.z, 9f32);
    }

    #[test]
    fn test_negate() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.negate();

        assert_eq!(a.x, -1f32);
        assert_eq!(a.y, -2f32);
        assert_eq!(a.z, -3f32);
    }

    #[test]
    fn test_negate_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let mut b = Vector3f::new(0f32, 0f32, 0f32);

        a.negate_into(&mut b);

        assert_eq!(b.x, -1f32);
        assert_eq!(b.y, -2f32);
        assert_eq!(b.z, -3f32);
    }

    #[test]
    fn test_normalize() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.normalize();

        assert!((1f32 - a.length()).abs() <= std::f32::EPSILON);
    }

    #[test]
    fn test_normalize_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let mut b = Vector3f::new(0f32, 0f32, 0f32);

        a.normalize_into(&mut b);

        assert!((1f32 - b.length()).abs() <= std::f32::EPSILON);
    }

    #[test]
    fn test_set() {
        let mut a = Vector3f::new(0f32, 0f32, 0f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        a.set(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
        assert_eq!(a.z, 3f32);
    }

    #[test]
    fn test_sub() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(0f32, 1f32, 2f32);

        a.sub(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 1f32);
        assert_eq!(a.z, 1f32);
    }

    #[test]
    fn test_sub_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(0f32, 1f32, 2f32);
        let mut c = Vector3f::new(0f32, 0f32, 0f32);

        a.sub_into(&b, &mut c);

        assert_eq!(c.x, 1f32);
        assert_eq!(c.y, 1f32);
        assert_eq!(c.z, 1f32);
    }

    #[test]
    fn test_zero() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.zero();

        assert_eq!(a.x, 0f32);
        assert_eq!(a.y, 0f32);
        assert_eq!(a.z, 0f32);
    }
}
<commit_msg>add angle and angle cos impls<commit_after>use super::Vector;
use super::Vector3;

pub struct Vector3f {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Vector<f32> for Vector3f {
    fn add(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x += v.x;
        self.y += v.y;
        self.z += v.z;
        self
    }

    fn add_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
        dest.z = self.z + v.z;
    }

    fn angle(&self, v: &Vector3f) -> f32 {
        let mut cos = self.angle_cos(v);
        cos = cos.min(1f32);
        cos = cos.max(-1f32);
        cos.acos()
    }

    fn angle_cos(&self, v: &Vector3f) -> f32 {
        let self_len_squared = self.length_squared();
        let v_len_squared = v.length_squared();
        let dot = self.dot(v);
        dot / ((self_len_squared * v_len_squared).sqrt())
    }

    fn distance(&self, v: &Vector3f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector3f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        let dz = self.z - v.z;
        (dx * dx) + (dy * dy) + (dz * dz)
    }

    fn dot(&self, v: &Vector3f) -> f32 {
        (self.x * v.x) + (self.y * v.y) + (self.z * v.z)
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector3f) -> &mut Vector3f {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector3f, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector3f, b: &Vector3f) -> &mut Vector3f {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector3f, b: &Vector3f, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        self.length_squared().sqrt()
    }

    fn length_squared(&self) -> f32 {
        (self.x * self.x) + (self.y * self.y) + (self.z * self.z)
    }

    fn lerp(&mut self, other: &Vector3f, t: f32) -> &mut Vector3f {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector3f, t: f32, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Vector3f {
        self.x *= s;
        self.y *= s;
        self.z *= s;
        self
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector3f) {
        dest.x = self.x * s;
        dest.y = self.y * s;
        dest.z = self.z * s;
    }

    fn mul_vector(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x *= v.x;
        self.y *= v.y;
        self.z *= v.z;
        self
    }

    fn mul_vector_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        dest.x = self.x * v.x;
        dest.y = self.y * v.y;
        dest.z = self.z * v.z;
    }

    fn negate(&mut self) -> &mut Vector3f {
        self.x = -self.x;
        self.y = -self.y;
        self.z = -self.z;
        self
    }

    fn negate_into(&self, dest: &mut Vector3f) {
        dest.x = -self.x;
        dest.y = -self.y;
        dest.z = -self.z;
    }

    fn normalize(&mut self) -> &mut Vector3f {
        let inv_length = 1.0f32 / self.length();
        self.x *= inv_length;
        self.y *= inv_length;
        self.z *= inv_length;
        self
    }

    fn normalize_into(&self, dest: &mut Vector3f) {
        let inv_length = 1.0f32 / self.length();
        dest.x = self.x * inv_length;
        dest.y = self.y * inv_length;
        dest.z = self.z * inv_length;
    }

    fn set(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x = v.x;
        self.y = v.y;
        self.z = v.z;
        self
    }

    fn sub(&mut self, v: &Vector3f) -> &mut Vector3f {
        self.x -= v.x;
        self.y -= v.y;
        self.z -= v.z;
        self
    }

    fn sub_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        dest.x = self.x - v.x;
        dest.y = self.y - v.y;
        dest.z = self.z - v.z;
    }

    fn zero(&mut self) -> &mut Vector3f {
        self.x = 0f32;
        self.y = 0f32;
        self.z = 0f32;
        self
    }
}

impl Vector3<f32> for Vector3f {
    fn new(x: f32, y: f32, z: f32) -> Vector3f {
        Vector3f {
            x: x,
            y: y,
            z: z,
        }
    }

    fn add_components(&mut self, x: f32, y: f32, z: f32) -> &mut Vector3f {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, z: f32, dest: &mut Vector3f) {
        unimplemented!()
    }

    fn cross(&mut self, v: &Vector3f) -> &mut Vector3f {
        unimplemented!()
    }

    fn cross_into(&self, v: &Vector3f, dest: &mut Vector3f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector3;
    use super::Vector3f;

    use std;

    #[test]
    fn test_new() {
        let a = Vector3f::new(1f32, 2f32, 3f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
        assert_eq!(a.z, 3f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        a.add(&b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
        assert_eq!(a.z, 6f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);
        let mut c = Vector3f::new(0f32, 0f32, 0f32);

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 4f32);
        assert_eq!(c.z, 6f32);
    }

    #[test]
    fn test_angle() {
        let a = Vector3f::new(1f32, 0f32, 0f32);
        let b = Vector3f::new(0f32, 1f32, 0f32);

        let target_angle = 90f32.to_radians();
        let angle = a.angle(&b);

        assert!((target_angle - angle).abs() <= std::f32::EPSILON);
    }

    #[test]
    fn test_angle_cos() {
        let a = Vector3f::new(1f32, 0f32, 0f32);
        let b = Vector3f::new(0f32, 1f32, 0f32);

        let target_angle_cos = 90f32.to_radians().cos();
        let angle_cos = a.angle_cos(&b);

        assert!((target_angle_cos - angle_cos).abs() <= std::f32::EPSILON);
    }

    #[test]
    fn test_distance() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(-1f32, 2f32, 3f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(-1f32, 2f32, 3f32);

        let target_distance_sq = 4f32; // target distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }

    #[test]
    fn test_dot() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        let target_dot = 14f32;
        let dot = a.dot(&b);

        assert_eq!(target_dot, dot);
    }

    #[test]
    fn test_length() {
        let a = Vector3f::new(1f32, 2f32, 2f32);

        let target_length = 3f32;
        let length = a.length();

        assert_eq!(target_length, length);
    }

    #[test]
    fn test_length_squared() {
        let a = Vector3f::new(1f32, 2f32, 3f32);

        let target_length_sq = 14f32;
        let length_sq = a.length_squared();

        assert_eq!(target_length_sq, length_sq);
    }

    #[test]
    fn test_mul_scalar() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.mul_scalar(2f32);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
        assert_eq!(a.z, 6f32);
    }

    #[test]
    fn test_mul_scalar_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let mut b = Vector3f::new(0f32, 0f32, 0f32);

        a.mul_scalar_into(2f32, &mut b);

        assert_eq!(b.x, 2f32);
        assert_eq!(b.y, 4f32);
        assert_eq!(b.z, 6f32);
    }

    #[test]
    fn test_mul_vector(){
        let mut a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        a.mul_vector(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 4f32);
        assert_eq!(a.z, 9f32);
    }

    #[test]
    fn test_mul_vector_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);
        let mut c = Vector3f::new(0f32, 0f32, 0f32);

        a.mul_vector_into(&b, &mut c);

        assert_eq!(c.x, 1f32);
        assert_eq!(c.y, 4f32);
        assert_eq!(c.z, 9f32);
    }

    #[test]
    fn test_negate() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.negate();

        assert_eq!(a.x, -1f32);
        assert_eq!(a.y, -2f32);
        assert_eq!(a.z, -3f32);
    }

    #[test]
    fn test_negate_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let mut b = Vector3f::new(0f32, 0f32, 0f32);

        a.negate_into(&mut b);

        assert_eq!(b.x, -1f32);
        assert_eq!(b.y, -2f32);
        assert_eq!(b.z, -3f32);
    }

    #[test]
    fn test_normalize() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.normalize();

        assert!((1f32 - a.length()).abs() <= std::f32::EPSILON);
    }

    #[test]
    fn test_normalize_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let mut b = Vector3f::new(0f32, 0f32, 0f32);

        a.normalize_into(&mut b);

        assert!((1f32 - b.length()).abs() <= std::f32::EPSILON);
    }

    #[test]
    fn test_set() {
        let mut a = Vector3f::new(0f32, 0f32, 0f32);
        let b = Vector3f::new(1f32, 2f32, 3f32);

        a.set(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
        assert_eq!(a.z, 3f32);
    }

    #[test]
    fn test_sub() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(0f32, 1f32, 2f32);

        a.sub(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 1f32);
        assert_eq!(a.z, 1f32);
    }

    #[test]
    fn test_sub_into() {
        let a = Vector3f::new(1f32, 2f32, 3f32);
        let b = Vector3f::new(0f32, 1f32, 2f32);
        let mut c = Vector3f::new(0f32, 0f32, 0f32);

        a.sub_into(&b, &mut c);

        assert_eq!(c.x, 1f32);
        assert_eq!(c.y, 1f32);
        assert_eq!(c.z, 1f32);
    }

    #[test]
    fn test_zero() {
        let mut a = Vector3f::new(1f32, 2f32, 3f32);

        a.zero();

        assert_eq!(a.x, 0f32);
        assert_eq!(a.y, 0f32);
        assert_eq!(a.z, 0f32);
    }
}
<|endoftext|>