<commit_before>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}
<commit_msg>Add SIMD vector-vector ops for V2 and V3<commit_after>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}
<|endoftext|>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    let product = v1.dot(v2);

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

    let product = v1.cross(v2);

    assert_eq!(product[0], 0.0);
    assert_eq!(product[1], 0.0);
    assert_eq!(product[2], 1.0);
  }
}<commit_msg>Add unit vector function and two tests<commit_after>use std::ops::{
  Add, AddAssign,
  Sub, SubAssign,
  Mul, MulAssign,
  Div, DivAssign,
  Index, IndexMut,
};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    let product = v1.dot(v2);

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

    let product = v1.cross(v2);

    assert_eq!(product[0], 0.0);
    assert_eq!(product[1], 0.0);
    assert_eq!(product[2], 1.0);
  }
  #[test]
  fn calculate_unit_vector_simple() {
    let v1 = Vec3 { i: 4.0, j: 0.0, k: 0.0};

    let product = v1.unit_vector();

    assert_eq!(product[0], 1.0);
    assert_eq!(product[1], 0.0);
    assert_eq!(product[2], 0.0);
  }
  #[test]
  fn calculate_unit_vector_multple() {
    let v1 = Vec3 { i: 4.0, j: 4.0, k: 2.0};

    let product = v1.unit_vector();

    assert_eq!(product[0], 4.0 / 6.0);
    assert_eq!(product[1], 4.0 / 6.0);
    assert_eq!(product[2], 2.0 / 6.0);
  }
}<|endoftext|>


<commit_before>extern crate handlebars;
#[macro_use]
extern crate serde_json;

use handlebars::{Handlebars, RenderError, Helper, RenderContext};
use serde_json::Value;

fn is_truthy(v: &Value) -> bool {
    match *v {
        Value::Bool(ref i) => *i,
        Value::Number(ref n) => n.as_f64().map(|f| f.is_normal()).unwrap_or(false),
        Value::Null => false,
        Value::String(ref i) => i.len() > 0,
        Value::Array(ref i) => i.len() > 0,
        Value::Object(ref i) => i.len() > 0,
    }
}

#[test]
fn test_subexpression() {
    let mut hbs = Handlebars::new();

    hbs.register_helper(
        "gt",
        Box::new(|h: &Helper,
         _: &Handlebars,
         rc: &mut RenderContext|
         -> Result<(), RenderError> {
            let p1 = try!(h.param(0).and_then(|v| v.value().as_i64()).ok_or(
                RenderError::new("Param 0 with i64 type is required for gt helper."),
            ));
            let p2 = try!(h.param(1).and_then(|v| v.value().as_i64()).ok_or(
                RenderError::new("Param 1 with i64 type is required for gt helper."),
            ));

            if p1 > p2 {
                rc.writer.write("true".as_bytes())?;
            }

            Ok(())
        }),
    );

    hbs.register_helper(
        "not",
        Box::new(|h: &Helper,
         _: &Handlebars,
         rc: &mut RenderContext|
         -> Result<(), RenderError> {
            let p1 = h.param(0).map(|v| is_truthy(v.value())).unwrap_or(false);
            if !p1 {
                rc.writer.write("true".as_bytes())?;
            }
            Ok(())
        }),
    );

    let data = json!({"a": 1, "b": 0, "c": 2});

    assert_eq!(
        hbs.template_render(
            "{{#if (gt a b)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Success"
    );

    assert_eq!(
        hbs.template_render(
            "{{#if (gt a c)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );

    assert_eq!(
        hbs.template_render(
            "{{#if (not (gt a c))}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Success"
    );

    assert_eq!(
        hbs.template_render(
            "{{#if (not (gt a b))}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );

    // no argument provided for not
    assert_eq!(
        hbs.template_render(
            "{{#if (not)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );

    // json literal
    assert_eq!(
        hbs.template_render(
            "{{#if (not true)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );
    assert_eq!(
        hbs.template_render(
            "{{#if (not false)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Success"
    );
}
<commit_msg>(test) update test for typed subexpression<commit_after>extern crate handlebars;
#[macro_use]
extern crate serde_json;

use handlebars::{Handlebars, RenderError, Helper, RenderContext, HelperDef};
use serde_json::Value;

struct GtHelper;

impl HelperDef for GtHelper {
    fn call_inner(
        &self,
        h: &Helper,
        _: &Handlebars,
        _: &mut RenderContext,
    ) -> Result<Option<Value>, RenderError> {
        let p1 = try!(h.param(0).and_then(|v| v.value().as_i64()).ok_or(
            RenderError::new("Param 0 with i64 type is required for gt helper."),
        ));
        let p2 = try!(h.param(1).and_then(|v| v.value().as_i64()).ok_or(
            RenderError::new("Param 1 with i64 type is required for gt helper."),
        ));

        Ok(Some(Value::Bool(p1 > p2)))
    }
}

struct NotHelper;

impl HelperDef for NotHelper {
    fn call_inner(
        &self,
        h: &Helper,
        _: &Handlebars,
        _: &mut RenderContext,
    ) -> Result<Option<Value>, RenderError> {
        let p1 = try!(h.param(0).and_then(|v| v.value().as_bool()).ok_or(
            RenderError::new("Param 0 with bool type is required for not helper."),
        ));

        Ok(Some(Value::Bool(!p1)))
    }
}

#[test]
fn test_subexpression() {
    let mut hbs = Handlebars::new();

    hbs.register_helper("gt", Box::new(GtHelper));
    hbs.register_helper("not", Box::new(NotHelper));

    let data = json!({"a": 1, "b": 0, "c": 2});

    assert_eq!(
        hbs.template_render(
            "{{#if (gt a b)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Success"
    );

    assert_eq!(
        hbs.template_render(
            "{{#if (gt a c)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );

    assert_eq!(
        hbs.template_render(
            "{{#if (not (gt a c))}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Success"
    );

    assert_eq!(
        hbs.template_render(
            "{{#if (not (gt a b))}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );

    // no argument provided for not
    assert_eq!(
        hbs.template_render(
            "{{#if (not)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );

    // json literal
    assert_eq!(
        hbs.template_render(
            "{{#if (not true)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Failed"
    );
    assert_eq!(
        hbs.template_render(
            "{{#if (not false)}}Success{{else}}Failed{{/if}}",
            &data,
        ).unwrap(),
        "Success"
    );
}
<|endoftext|>


<commit_before>use jsonrpc_types::rpc_types::Filter;
use std::collections::HashMap;
use std::time::SystemTime;

// TODO Refactor:
// * use generic data type
// * use one hashmap: use tuple type
//
// ```rust
// struct FilterData<T> {
//     data: HashMap<usize, T>,
// }
//      ```
#[derive(Default)]
pub struct BlockFilter {
    /// To save the filter for filter_blocks
    data: HashMap<usize, u64>,
}

impl BlockFilter {
    fn is_filter(&self, id: usize) -> bool {
        self.data.contains_key(&id)
    }

    fn insert(&mut self, id: usize, filter: u64) {
        self.data.insert(id, filter);
    }

    fn remove(&mut self, id: usize) {
        self.data.remove(&id);
    }

    fn get(&self, id: usize) -> Option<&u64> {
        self.data.get(&id)
    }
}

#[derive(Default)]
pub struct LogsFilter {
    /// To save the filter for filter_logs
    data: HashMap<usize, Filter>,
}

impl LogsFilter {
    fn is_filter(&self, id: usize) -> bool {
        self.data.contains_key(&id)
    }

    fn insert(&mut self, id: usize, filter: Filter) {
        self.data.insert(id, filter);
    }

    fn remove(&mut self, id: usize) {
        self.data.remove(&id);
    }

    fn get(&self, id: usize) -> Option<&Filter> {
        self.data.get(&id)
    }
}

#[derive(Default)]
pub struct FilterDB {
    /// Self-increase ID.
    next_available_id: usize,
    /// To save the last update timestamp
    last_update: HashMap<usize, u64>,
    /// Refactor: Note: logs filter includes block filter.
    block_filter: BlockFilter,
    logs_filter: LogsFilter,
    /// lifetime of fileter id
    lifetime: u32,
}

impl FilterDB {
    pub fn new() -> Self {
        FilterDB {
            // Set the lifetime: 60s
            lifetime: 60,
            ..Default::default()
        }
    }

    #[cfg(test)]
    pub fn set_lifetime(&mut self, lifetime: u32) {
        self.lifetime = lifetime;
    }

    /// Generate a new fresh id
    /// Prune the hashmap first.
    pub fn gen_id(&mut self) -> usize {
        self.prune();
        let id = self.next_available_id;
        self.next_available_id = self.next_available_id.wrapping_add(1);
        id
    }

    /// Generate a new normal filter
    pub fn gen_logs_filter(&mut self, id: usize, filter: Filter) {
        let now = now();
        self.last_update.insert(id, now);
        self.logs_filter.insert(id, filter);
    }

    /// Generate a new filter for block
    pub fn gen_block_filter(&mut self, id: usize, filter: u64) {
        let now = now();
        self.last_update.insert(id, now);
        self.block_filter.insert(id, filter);
    }

    /// Uninstall the filter id
    pub fn uninstall(&mut self, id: usize) -> bool {
        // Remove logs first. casue logs filter includes the block filter.
        if self.is_logs_filter(id) {
            self.logs_filter.remove(id);
            true
        } else if self.is_block_filter(id) {
            self.block_filter.remove(id);
            true
        } else {
            false
        }
    }

    /// Prune the overdue id manually
    /// Remove all the ids that: (now-lastupdate) > self.lifetime
    pub fn prune(&mut self) {
        let now = now();
        for (id, time) in self.last_update.clone().iter() {
            if (now - *time) >= self.lifetime.into() {
                trace!("Prune filter, time: {:?}", (now - *time));
                self.block_filter.remove(*id);
                self.logs_filter.remove(*id);
            }
        }
    }

    /// Get the filter for logs.
    /// Prune the hashmap first.
    pub fn get_logs_filter(&mut self, id: usize) -> Option<&Filter> {
        let now = now();
        trace!("Get logs filter: {:?}", self.logs_filter.get(id));
        self.prune();
        self.last_update.insert(id, now);
        self.logs_filter.get(id)
    }

    /// Get the filter for block
    /// Prune the hashmap first.
    pub fn get_block_filter(&mut self, id: usize) -> Option<&u64> {
        let now = now();
        trace!("Get block filter: {:?}", self.block_filter.get(id));
        self.prune();
        self.last_update.insert(id, now);
        self.block_filter.get(id)
    }

    /// Check the id is for block filter:
    /// Check the log, too. cause the logs filter also insert block filter.
    pub fn is_block_filter(&self, id: usize) -> bool {
        self.block_filter.is_filter(id) && !self.logs_filter.is_filter(id)
    }

    /// Check the id is for logs
    pub fn is_logs_filter(&self, id: usize) -> bool {
        self.logs_filter.is_filter(id)
    }

    /// Check the id is block filter or logs filter
    pub fn is_filter(&self, id: usize) -> bool {
        self.logs_filter.is_filter(id) || self.block_filter.is_filter(id)
    }
}

/// Generate the now time
fn now() -> u64 {
    SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

#[cfg(test)]
mod tests {
    use super::FilterDB;
    use jsonrpc_types::rpc_types::BlockNumber;
    use jsonrpc_types::rpc_types::Filter;

    #[test]
    fn test_gen_id() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.next_available_id;
        filterdb.gen_id();
        assert_eq!(filterdb.next_available_id, id + 1);
    }

    #[test]
    fn test_gen_logs_filter_and_uninstall() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.gen_id();
        let filter = Filter::new(BlockNumber::earliest(), BlockNumber::earliest(), None, None);
        assert_eq!(filterdb.is_logs_filter(id), false);
        assert_eq!(filterdb.get_logs_filter(id), None);
        // Gen logs filter
        filterdb.gen_logs_filter(id, filter.clone());
        assert_eq!(filterdb.is_logs_filter(id), true);
        assert_eq!(*filterdb.get_logs_filter(id).unwrap(), filter);
        // Uninstall
        filterdb.uninstall(id);
        assert_eq!(filterdb.is_block_filter(id), false);
        assert_eq!(filterdb.get_block_filter(id), None);
    }

    #[test]
    fn test_gen_block_filter_and_uninstall() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.gen_id();
        let filter = 0;
        assert_eq!(filterdb.is_block_filter(id), false);
        assert_eq!(filterdb.get_block_filter(id), None);
        // Gen block filter
        filterdb.gen_block_filter(id, filter.clone());
        assert_eq!(filterdb.is_block_filter(id), true);
        assert_eq!(*filterdb.get_block_filter(id).unwrap(), filter);
        // Uninstall
        filterdb.uninstall(id);
        assert_eq!(filterdb.is_block_filter(id), false);
        assert_eq!(filterdb.get_block_filter(id), None);
    }

    #[test]
    fn test_prune() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.gen_id();
        let filter = 0;
        filterdb.gen_block_filter(id, filter.clone());
        assert_eq!(filterdb.is_filter(id), true);
        assert_eq!(*filterdb.get_block_filter(id).unwrap(), filter);
        filterdb.set_lifetime(0);
        assert_eq!(filterdb.lifetime, 0);
        filterdb.prune();
        assert_eq!(filterdb.get_block_filter(id), None);
        assert_eq!(filterdb.is_filter(id), false);
    }
}
<commit_msg>Prune the hahsmap when uninstall filter id.<commit_after>use jsonrpc_types::rpc_types::Filter;
use std::collections::HashMap;
use std::time::SystemTime;

// TODO Refactor:
// * use generic data type
// * use one hashmap: use tuple type
//
// ```rust
// struct FilterData<T> {
//     data: HashMap<usize, T>,
// }
//      ```
#[derive(Default)]
pub struct BlockFilter {
    /// To save the filter for filter_blocks
    data: HashMap<usize, u64>,
}

impl BlockFilter {
    fn is_filter(&self, id: usize) -> bool {
        self.data.contains_key(&id)
    }

    fn insert(&mut self, id: usize, filter: u64) {
        self.data.insert(id, filter);
    }

    fn remove(&mut self, id: usize) {
        self.data.remove(&id);
    }

    fn get(&self, id: usize) -> Option<&u64> {
        self.data.get(&id)
    }
}

#[derive(Default)]
pub struct LogsFilter {
    /// To save the filter for filter_logs
    data: HashMap<usize, Filter>,
}

impl LogsFilter {
    fn is_filter(&self, id: usize) -> bool {
        self.data.contains_key(&id)
    }

    fn insert(&mut self, id: usize, filter: Filter) {
        self.data.insert(id, filter);
    }

    fn remove(&mut self, id: usize) {
        self.data.remove(&id);
    }

    fn get(&self, id: usize) -> Option<&Filter> {
        self.data.get(&id)
    }
}

#[derive(Default)]
pub struct FilterDB {
    /// Self-increase ID.
    next_available_id: usize,
    /// To save the last update timestamp
    last_update: HashMap<usize, u64>,
    /// Refactor: Note: logs filter includes block filter.
    block_filter: BlockFilter,
    logs_filter: LogsFilter,
    /// lifetime of fileter id
    lifetime: u32,
}

impl FilterDB {
    pub fn new() -> Self {
        FilterDB {
            // Set the lifetime: 60s
            lifetime: 60,
            ..Default::default()
        }
    }

    #[cfg(test)]
    pub fn set_lifetime(&mut self, lifetime: u32) {
        self.lifetime = lifetime;
    }

    /// Generate a new fresh id
    /// Prune the hashmap first.
    pub fn gen_id(&mut self) -> usize {
        self.prune();
        let id = self.next_available_id;
        self.next_available_id = self.next_available_id.wrapping_add(1);
        id
    }

    /// Generate a new normal filter
    pub fn gen_logs_filter(&mut self, id: usize, filter: Filter) {
        let now = now();
        self.last_update.insert(id, now);
        self.logs_filter.insert(id, filter);
    }

    /// Generate a new filter for block
    pub fn gen_block_filter(&mut self, id: usize, filter: u64) {
        let now = now();
        self.last_update.insert(id, now);
        self.block_filter.insert(id, filter);
    }

    /// Uninstall the filter id
    pub fn uninstall(&mut self, id: usize) -> bool {
        self.prune();
        // Remove logs first. casue logs filter includes the block filter.
        if self.is_logs_filter(id) {
            self.logs_filter.remove(id);
            true
        } else if self.is_block_filter(id) {
            self.block_filter.remove(id);
            true
        } else {
            false
        }
    }

    /// Prune the overdue id manually
    /// Remove all the ids that: (now-lastupdate) > self.lifetime
    pub fn prune(&mut self) {
        let now = now();
        for (id, time) in self.last_update.clone().iter() {
            if (now - *time) >= self.lifetime.into() {
                trace!("Prune filter, time: {:?}", (now - *time));
                self.block_filter.remove(*id);
                self.logs_filter.remove(*id);
            }
        }
    }

    /// Get the filter for logs.
    /// Prune the hashmap first.
    pub fn get_logs_filter(&mut self, id: usize) -> Option<&Filter> {
        let now = now();
        trace!("Get logs filter: {:?}", self.logs_filter.get(id));
        self.prune();
        self.last_update.insert(id, now);
        self.logs_filter.get(id)
    }

    /// Get the filter for block
    /// Prune the hashmap first.
    pub fn get_block_filter(&mut self, id: usize) -> Option<&u64> {
        let now = now();
        trace!("Get block filter: {:?}", self.block_filter.get(id));
        self.prune();
        self.last_update.insert(id, now);
        self.block_filter.get(id)
    }

    /// Check the id is for block filter:
    /// Check the log, too. cause the logs filter also insert block filter.
    pub fn is_block_filter(&self, id: usize) -> bool {
        self.block_filter.is_filter(id) && !self.logs_filter.is_filter(id)
    }

    /// Check the id is for logs
    pub fn is_logs_filter(&self, id: usize) -> bool {
        self.logs_filter.is_filter(id)
    }

    /// Check the id is block filter or logs filter
    pub fn is_filter(&self, id: usize) -> bool {
        self.logs_filter.is_filter(id) || self.block_filter.is_filter(id)
    }
}

/// Generate the now time
fn now() -> u64 {
    SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

#[cfg(test)]
mod tests {
    use super::FilterDB;
    use jsonrpc_types::rpc_types::BlockNumber;
    use jsonrpc_types::rpc_types::Filter;

    #[test]
    fn test_gen_id() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.next_available_id;
        filterdb.gen_id();
        assert_eq!(filterdb.next_available_id, id + 1);
    }

    #[test]
    fn test_gen_logs_filter_and_uninstall() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.gen_id();
        let filter = Filter::new(BlockNumber::earliest(), BlockNumber::earliest(), None, None);
        assert_eq!(filterdb.is_logs_filter(id), false);
        assert_eq!(filterdb.get_logs_filter(id), None);
        // Gen logs filter
        filterdb.gen_logs_filter(id, filter.clone());
        assert_eq!(filterdb.is_logs_filter(id), true);
        assert_eq!(*filterdb.get_logs_filter(id).unwrap(), filter);
        // Uninstall
        filterdb.uninstall(id);
        assert_eq!(filterdb.is_block_filter(id), false);
        assert_eq!(filterdb.get_block_filter(id), None);
    }

    #[test]
    fn test_gen_block_filter_and_uninstall() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.gen_id();
        let filter = 0;
        assert_eq!(filterdb.is_block_filter(id), false);
        assert_eq!(filterdb.get_block_filter(id), None);
        // Gen block filter
        filterdb.gen_block_filter(id, filter.clone());
        assert_eq!(filterdb.is_block_filter(id), true);
        assert_eq!(*filterdb.get_block_filter(id).unwrap(), filter);
        // Uninstall
        filterdb.uninstall(id);
        assert_eq!(filterdb.is_block_filter(id), false);
        assert_eq!(filterdb.get_block_filter(id), None);
    }

    #[test]
    fn test_prune() {
        let mut filterdb = FilterDB::new();
        let id = filterdb.gen_id();
        let filter = 0;
        filterdb.gen_block_filter(id, filter.clone());
        assert_eq!(filterdb.is_filter(id), true);
        assert_eq!(*filterdb.get_block_filter(id).unwrap(), filter);
        filterdb.set_lifetime(0);
        assert_eq!(filterdb.lifetime, 0);
        filterdb.prune();
        assert_eq!(filterdb.get_block_filter(id), None);
        assert_eq!(filterdb.is_filter(id), false);
    }
}
<|endoftext|>


<commit_before>pub mod bytecode;
pub mod vm;

use frontend::scanner;
use user_interface::{RuloxImplementation, RunResult as UiRunResult};

pub struct RuloxVm {}

impl RuloxVm {
    pub fn new() -> RuloxVm {
        RuloxVm {}
    }
}

impl RuloxImplementation for RuloxVm {
    fn run(&mut self, source: &str) -> UiRunResult {
        let mut errors = vec![];
        for scan_result in scanner::scan_into_iterator(source) {
            match scan_result {
                Ok(token_with_context) => println!("{:?}", token_with_context),
                Err(error) => errors.push(error), //TODO: wrap in generic error
            }
        }
        UiRunResult::Error //TODO: implement
    }
}

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

    proptest! {
    #[test]
    fn doesnt_crash(ref input in "\\PC*") {
        let mut ruloxvm = RuloxVm::new();
        ruloxvm.run(input)
    }
    }
}
<commit_msg>Sketched compiler<commit_after>pub mod bytecode;
pub mod compiler;
pub mod vm;

use frontend::scanner;
use user_interface::{RuloxImplementation, RunResult as UiRunResult};

pub struct RuloxVm {}

impl RuloxVm {
    pub fn new() -> RuloxVm {
        RuloxVm {}
    }
}

impl RuloxImplementation for RuloxVm {
    fn run(&mut self, source: &str) -> UiRunResult {
        let mut errors = vec![];
        for scan_result in scanner::scan_into_iterator(source) {
            match scan_result {
                Ok(token_with_context) => println!("{:?}", token_with_context),
                Err(error) => errors.push(error), //TODO: wrap in generic error
            }
        }
        UiRunResult::Error //TODO: implement
    }
}

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

    proptest! {
    #[test]
    fn doesnt_crash(ref input in "\\PC*") {
        let mut ruloxvm = RuloxVm::new();
        ruloxvm.run(input)
    }
    }
}
<|endoftext|>


<commit_before>use ffi;
use std::os::raw::c_int;
use types::{Result, PortMidiDeviceId, Error};
use io::{InputPort, OutputPort};
use device::DeviceInfo;

/// The PortMidi base struct.
/// Initializes PortMidi on creation and terminates it on drop.
pub struct PortMidi {
    device_cnt: u32,
}
impl PortMidi {
    /// Initializes the underlying PortMidi C library.
    /// PortMidi does not support *hot plugging*, this means
    /// that devices that are connect after calling `new`
    /// are not picked up.
    pub fn new() -> Result<Self> {
        try!(Result::from(unsafe { ffi::Pm_Initialize() }));
        let device_cnt = unsafe { ffi::Pm_CountDevices() };
        if device_cnt >= 0 {
            Ok(PortMidi { device_cnt: device_cnt as u32 })
        } else {
            Err(Error::Invalid)
        }
    }

    /// Return the number of devices. This number will not change during the lifetime
    /// of the program.
    pub fn device_cnt(&self) -> PortMidiDeviceId {
        self.device_cnt as c_int
    }

    /// Returns the `PortMidiDeviceId` for the default input device, or an `Error::NoDefaultDevice` if
    /// there is no available.
    pub fn default_input_device_id(&self) -> Result<PortMidiDeviceId> {
        match unsafe { ffi::Pm_GetDefaultInputDeviceID() } {
            ffi::PM_NO_DEVICE => Err(Error::NoDefaultDevice),
            id @ _ => Ok(id),
        }
    }

    /// Returns the `PortMidiDeviceId` for the default output device, or an `Error::NoDefaultDevice` if
    /// there is no available.
    pub fn default_output_device_id(&self) -> Result<PortMidiDeviceId> {
        match unsafe { ffi::Pm_GetDefaultOutputDeviceID() } {
            ffi::PM_NO_DEVICE => Err(Error::NoDefaultDevice),
            id @ _ => Ok(id),
        }
    }

    /// Returns the `DeviceInfo` for the given device id or an `Error::PortMidi(_)` if
    /// the given id is invalid.
    pub fn device(&self, id: PortMidiDeviceId) -> Result<DeviceInfo> {
        DeviceInfo::new(id)
    }

    /// Returns a `Vec<DeviceInfo>` containing all known device infos.
    /// An `Error::PortMidi(_)` is returned if the info for a device can't be obtained.
    pub fn devices(&self) -> Result<Vec<DeviceInfo>> {
        let mut devices = Vec::with_capacity(self.device_cnt() as usize);
        for res in (0..self.device_cnt()).map(|id| self.device(id)) {
            match res {
                Ok(device) => devices.push(device),
                Err(err) => return Err(err),
            }
        }
        Ok(devices)
    }

    /// Creates an `InputPort` instance with the given buffer size for the default input device.
    pub fn default_input_port(&self, buffer_size: usize) -> Result<InputPort> {
        let info = try!(self.default_input_device_id().and_then(|id| self.device(id)));
        InputPort::new(info, buffer_size)
    }

    /// Creates an `InputPort` instance for the given device and buffer size.
    /// If the given device is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn input_port(&self, device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_input() {
            InputPort::new(device, buffer_size)
        } else {
            Err(Error::NotAnInputDevice)
        }
    }

    /// Creates an `OutputPort` instance with the given buffer size for the default output device.
    pub fn default_output_port(&self, buffer_size: usize) -> Result<OutputPort> {
        let info = try!(self.default_output_device_id().and_then(|id| self.device(id)));
        OutputPort::new(info, buffer_size)
    }

    /// Creates an `OutputPort` instance for the given device and buffer size.
    /// If the given device is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn output_port(&self, device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_output() {
            OutputPort::new(device, buffer_size)
        } else {
            Err(Error::NotAnOutputDevice)
        }
    }
}
impl Drop for PortMidi {
    fn drop(&mut self) {
        Result::from(unsafe { ffi::Pm_Terminate() })
            .map_err(|err| println!("Could not terminate: {}", err));
    }
}
<commit_msg>Use result in Drop: panic on termination error<commit_after>use ffi;
use std::os::raw::c_int;
use types::{Result, PortMidiDeviceId, Error};
use io::{InputPort, OutputPort};
use device::DeviceInfo;

/// The PortMidi base struct.
/// Initializes PortMidi on creation and terminates it on drop.
pub struct PortMidi {
    device_cnt: u32,
}
impl PortMidi {
    /// Initializes the underlying PortMidi C library.
    /// PortMidi does not support *hot plugging*, this means
    /// that devices that are connect after calling `new`
    /// are not picked up.
    pub fn new() -> Result<Self> {
        try!(Result::from(unsafe { ffi::Pm_Initialize() }));
        let device_cnt = unsafe { ffi::Pm_CountDevices() };
        if device_cnt >= 0 {
            Ok(PortMidi { device_cnt: device_cnt as u32 })
        } else {
            Err(Error::Invalid)
        }
    }

    /// Return the number of devices. This number will not change during the lifetime
    /// of the program.
    pub fn device_cnt(&self) -> PortMidiDeviceId {
        self.device_cnt as c_int
    }

    /// Returns the `PortMidiDeviceId` for the default input device, or an `Error::NoDefaultDevice` if
    /// there is no available.
    pub fn default_input_device_id(&self) -> Result<PortMidiDeviceId> {
        match unsafe { ffi::Pm_GetDefaultInputDeviceID() } {
            ffi::PM_NO_DEVICE => Err(Error::NoDefaultDevice),
            id @ _ => Ok(id),
        }
    }

    /// Returns the `PortMidiDeviceId` for the default output device, or an `Error::NoDefaultDevice` if
    /// there is no available.
    pub fn default_output_device_id(&self) -> Result<PortMidiDeviceId> {
        match unsafe { ffi::Pm_GetDefaultOutputDeviceID() } {
            ffi::PM_NO_DEVICE => Err(Error::NoDefaultDevice),
            id @ _ => Ok(id),
        }
    }

    /// Returns the `DeviceInfo` for the given device id or an `Error::PortMidi(_)` if
    /// the given id is invalid.
    pub fn device(&self, id: PortMidiDeviceId) -> Result<DeviceInfo> {
        DeviceInfo::new(id)
    }

    /// Returns a `Vec<DeviceInfo>` containing all known device infos.
    /// An `Error::PortMidi(_)` is returned if the info for a device can't be obtained.
    pub fn devices(&self) -> Result<Vec<DeviceInfo>> {
        let mut devices = Vec::with_capacity(self.device_cnt() as usize);
        for res in (0..self.device_cnt()).map(|id| self.device(id)) {
            match res {
                Ok(device) => devices.push(device),
                Err(err) => return Err(err),
            }
        }
        Ok(devices)
    }

    /// Creates an `InputPort` instance with the given buffer size for the default input device.
    pub fn default_input_port(&self, buffer_size: usize) -> Result<InputPort> {
        let info = try!(self.default_input_device_id().and_then(|id| self.device(id)));
        InputPort::new(info, buffer_size)
    }

    /// Creates an `InputPort` instance for the given device and buffer size.
    /// If the given device is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn input_port(&self, device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_input() {
            InputPort::new(device, buffer_size)
        } else {
            Err(Error::NotAnInputDevice)
        }
    }

    /// Creates an `OutputPort` instance with the given buffer size for the default output device.
    pub fn default_output_port(&self, buffer_size: usize) -> Result<OutputPort> {
        let info = try!(self.default_output_device_id().and_then(|id| self.device(id)));
        OutputPort::new(info, buffer_size)
    }

    /// Creates an `OutputPort` instance for the given device and buffer size.
    /// If the given device is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn output_port(&self, device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_output() {
            OutputPort::new(device, buffer_size)
        } else {
            Err(Error::NotAnOutputDevice)
        }
    }
}
impl Drop for PortMidi {
    fn drop(&mut self) {
        Result::from(unsafe { ffi::Pm_Terminate() })
            .map_err(|err| println!("Could not terminate: {}", err)).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use super::condition_register::ConditionRegister;
use super::exception::Exception;
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::time_base_register::TimeBaseRegister;
use super::super::interconnect::Interconnect;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub interconnect: Interconnect,
    pub mmu: mmu::Mmu,
    cia: u32,
    nia: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: ConditionRegister,
    lr: u32,
    tb: TimeBaseRegister
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        let mut cpu = Cpu {
            interconnect: interconnect,
            mmu: mmu::Mmu::new(),
            cia: 0,
            nia: 0,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: MachineStatus::default(),
            sr: [0; NUM_SR],
            cr: ConditionRegister::default(),
            lr: 0,
            tb: TimeBaseRegister::default()
        };

        cpu.exception(Exception::SystemReset); // power on reset
        cpu
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x} {}", self.cia, instr.opcode());

        self.nia = self.cia + 4;

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    16 => self.bclrx(instr),
                    150 => self.isync(instr),
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     40 => self.subfx(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.cia = self.nia;

        // tick timer
        self.tb.advance();
    }

    fn read_instruction(&mut self) -> Instruction {
        let addr = self.mmu.translate_address(mmu::BatType::Instruction, &self.msr, self.cia);

        Instruction(self.interconnect.read_word(addr))
    }

    // FixMe: handle exceptions properly
    pub fn exception(&mut self, e: Exception) {
        let nia = match e {
            Exception::SystemReset => 0x00100
        };

        if self.msr.exception_prefix {
            self.cia = nia ^ 0xFFF00000
        } else {
            self.cia = nia
        }

        println!("{:#x} exception occurred, nia {:#x}", nia, self.cia);
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();
        let mut c:u8;

        if a < b {
            c = 0b1000;
        } else if a > b {
            c = 0b0100;
        } else {
            c = 0b0010;
        }

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // branch conditional
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        println!("bc: {:#?}", self.cr);

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.nia = sign_ext_16(instr.bd() << 2) as u32;
            } else {
                self.nia = self.cia.wrapping_add(sign_ext_16(instr.bd() << 2) as u32);
            }

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.nia = sign_ext_26(instr.li() << 2) as u32;
        } else {
            self.nia = self.cia.wrapping_add(sign_ext_26(instr.li() << 2) as u32);
        }

        if instr.lk() == 1 {
            self.lr = self.cia + 4;
        }
    }

    // branch conditional to link register
    fn bclrx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            self.nia = self.lr & 0b00;

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    #[allow(unused_variables)]
    // isync - instruction synchronize
    fn isync(&mut self, instr: Instruction) {
        // don't do anything
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.a()] as u8);
        }
    }

    // subtract from
    fn subfx(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()].wrapping_sub(self.gpr[instr.b()]);

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.d()] as u8);
        }

        // TODO: update XER if OE = 1
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.gpr[instr.s()] = self.lr,
            9 => self.gpr[instr.s()] = self.ctr,
            _ => {
                println!("FIXME: spr {} not implemented", n);
                self.gpr[instr.s()] = self.spr[n];
            }
        }

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => self.gpr[instr.d()] = self.tb.l(),
            269 => self.gpr[instr.d()] = self.tb.u(),
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => {
                println!("FIXME: mtspr {} not implemented", n);
                self.spr[n] = self.gpr[instr.s()];
            }
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.gpr[instr.d()] = self.interconnect.read_word(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_word(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_halfword(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

// Note: A cast from a signed value widens with signed-extension
//       A cast from an unsigned value widens with zero-extension
fn sign_ext_16(x: u16) -> i32 {
    (x as i16) as i32
}

fn sign_ext_26(x: u32) -> i32 {
    if x & 0x2000000 != 0 {
        (x | 0xFC000000) as i32
    } else {
        x as i32
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<commit_msg>implemented cmpl instruction<commit_after>use std::fmt;

use super::condition_register::ConditionRegister;
use super::exception::Exception;
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::time_base_register::TimeBaseRegister;
use super::super::interconnect::Interconnect;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub interconnect: Interconnect,
    pub mmu: mmu::Mmu,
    cia: u32,
    nia: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: ConditionRegister,
    lr: u32,
    tb: TimeBaseRegister
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        let mut cpu = Cpu {
            interconnect: interconnect,
            mmu: mmu::Mmu::new(),
            cia: 0,
            nia: 0,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: MachineStatus::default(),
            sr: [0; NUM_SR],
            cr: ConditionRegister::default(),
            lr: 0,
            tb: TimeBaseRegister::default()
        };

        cpu.exception(Exception::SystemReset); // power on reset
        cpu
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x} {}", self.cia, instr.opcode());

        self.nia = self.cia + 4;

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    16 => self.bclrx(instr),
                    150 => self.isync(instr),
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     32 => self.cmpl(instr),
                     40 => self.subfx(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.cia = self.nia;

        // tick timer
        self.tb.advance();
    }

    fn read_instruction(&mut self) -> Instruction {
        let addr = self.mmu.translate_address(mmu::BatType::Instruction, &self.msr, self.cia);

        Instruction(self.interconnect.read_word(addr))
    }

    // FixMe: handle exceptions properly
    pub fn exception(&mut self, e: Exception) {
        let nia = match e {
            Exception::SystemReset => 0x00100
        };

        if self.msr.exception_prefix {
            self.cia = nia ^ 0xFFF00000
        } else {
            self.cia = nia
        }

        println!("{:#x} exception occurred, nia {:#x}", nia, self.cia);
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();

        let mut c:u8 = if a < b {
            0b1000
        } else if a > b {
            0b0100
        } else {
            0b0010
        };

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // branch conditional
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.nia = sign_ext_16(instr.bd() << 2) as u32;
            } else {
                self.nia = self.cia.wrapping_add(sign_ext_16(instr.bd() << 2) as u32);
            }

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.nia = sign_ext_26(instr.li() << 2) as u32;
        } else {
            self.nia = self.cia.wrapping_add(sign_ext_26(instr.li() << 2) as u32);
        }

        if instr.lk() == 1 {
            self.lr = self.cia + 4;
        }
    }

    // branch conditional to link register
    fn bclrx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            self.nia = self.lr & 0b00;

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    #[allow(unused_variables)]
    // isync - instruction synchronize
    fn isync(&mut self, instr: Instruction) {
        // don't do anything
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.a()] as u8);
        }
    }

    // ToDo: if L = 1, instruction form is invalid
    fn cmpl(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = self.gpr[instr.b()];

        let mut c:u8 = if a < b {
            0b1000
        } else if a > b {
            0b0100
        } else {
            0b0010
        };

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // subtract from
    fn subfx(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()].wrapping_sub(self.gpr[instr.b()]);

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.d()] as u8);
        }

        // TODO: update XER if OE = 1
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.gpr[instr.s()] = self.lr,
            9 => self.gpr[instr.s()] = self.ctr,
            _ => {
                println!("FIXME: spr {} not implemented", n);
                self.gpr[instr.s()] = self.spr[n];
            }
        }

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => self.gpr[instr.d()] = self.tb.l(),
            269 => self.gpr[instr.d()] = self.tb.u(),
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => {
                println!("FIXME: mtspr {} not implemented", n);
                self.spr[n] = self.gpr[instr.s()];
            }
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.gpr[instr.d()] = self.interconnect.read_word(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_word(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_halfword(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

// Note: A cast from a signed value widens with signed-extension
//       A cast from an unsigned value widens with zero-extension
fn sign_ext_16(x: u16) -> i32 {
    (x as i16) as i32
}

fn sign_ext_26(x: u32) -> i32 {
    if x & 0x2000000 != 0 {
        (x | 0xFC000000) as i32
    } else {
        x as i32
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<|endoftext|>


<commit_before>#![macro_use]
use super::Core;
macro_rules! ir_dx {
	($e:ident) => (($e.ir >> 9 & 7) as usize);
}
macro_rules! ir_dy {
	($e:ident) => (($e.ir & 7) as usize);
}
macro_rules! ir_ax {
	($e:ident) => (8+($e.ir >> 9 & 7) as usize);
}
macro_rules! ir_ay {
	($e:ident) => (8+($e.ir & 7) as usize);
}
macro_rules! dx {
	($e:ident) => ($e.dar[ir_dx!($e)]);
}
macro_rules! dy {
	($e:ident) => ($e.dar[ir_dy!($e)]);
}
macro_rules! ax {
	($e:ident) => ($e.dar[ir_ax!($e)]);
}
macro_rules! ay {
	($e:ident) => ($e.dar[ir_ay!($e)]);
}
macro_rules! mask_out_above_8 {
	($e:expr) => ($e & 0xff)
}
macro_rules! mask_out_below_8 {
	($e:expr) => ($e & !0xff)
}
macro_rules! low_nibble {
	($e:expr) => ($e & 0x0f);
}
macro_rules! high_nibble {
	($e:expr) => ($e & 0xf0);
}
macro_rules! true1 {
	($e:expr) => (if $e {1} else {0})
}
macro_rules! not1 {
	($e:expr) => (true1!($e == 0))
}

pub mod fake {
	use super::super::Core;

	pub fn set_d0(core: &mut Core) {
		core.dar[0] = 0xabcd;
	}

	pub fn set_d1(core: &mut Core) {
		core.dar[1] = 0xbcde;
	}

	pub fn set_dx(core: &mut Core) {
		dx!(core) = 0xcdef;
	}

	use super::super::InstructionSet;
	use super::illegal;
	const SET_DX_0: usize = 0b0100_0000_0000_0000;

	pub fn instruction_set() -> InstructionSet {
		// Covers all possible IR values (64k entries)
		let mut handler: InstructionSet = Vec::with_capacity(0x10000);
		for _ in 0..0x10000 { handler.push(illegal); }
		handler[0xA] = set_d0;
		handler[0xB] = set_d1;
		for i in 0..8 {
			let opcode = SET_DX_0 | (i << 9);
			// println!("{:x}", opcode);
			handler[opcode] = set_dx;
		}
		handler
	}
}

pub fn illegal(core: &mut Core) {
	panic!("Illegal instruction {:04x} at {:08x}", core.ir, core.pc-2);
}

use std::num::Wrapping;
use super::operator;

// All instructions are ported from https://github.com/kstenerud/Musashi
pub fn abcd_8_common(core: &mut Core, dst: u32, src: u32) -> u32 {
	// unsigned int res = ((src) & 0x0f) + ((dst) & 0x0f) + ((m68ki_cpu.x_flag>>8)&1);
	let mut res = low_nibble!(src) + low_nibble!(dst) + core.x_flag_as_1();

	// m68ki_cpu.v_flag = ~res;
	core.v_flag = !res;

	// if(res > 9)
	//  res += 6;
	if res > 9 {
		res += 6;
	}
	// res += ((src) & 0xf0) + ((dst) & 0xf0);
	res += high_nibble!(src) + high_nibble!(dst);
	// m68ki_cpu.x_flag = m68ki_cpu.c_flag = (res > 0x99) << 8;
	core.c_flag = true1!(res > 0x99) << 8;
	core.x_flag = core.c_flag;

	if core.c_flag > 0 {
		res = (Wrapping(res) - Wrapping(0xa0)).0;
	}

	// m68ki_cpu.v_flag &= res;
	// m68ki_cpu.n_flag = (res);
	core.v_flag &= res;
	core.n_flag = res;

	// res = ((res) & 0xff);
	// m68ki_cpu.not_z_flag |= res;
	res = mask_out_above_8!(res);
	core.not_z_flag |= res;
	res
}
pub fn abcd_8_rr(core: &mut Core) {
	let dst = operator::dx(core);
	let src = operator::dy(core);
	let res = abcd_8_common(core, dst, src);
	dx!(core) = mask_out_below_8!(dst) | res;
}
pub fn abcd_8_mm(core: &mut Core) {
	let src = operator::ay_pd_8(core);
	let (dst, ea) = operator::ax_pd_8(core);
	let res = abcd_8_common(core, dst, src);
	core.write_data_byte(ea, res);
}

fn add_8_common(core: &mut Core, dst: u32, src: u32) -> u32 {
	let dst = mask_out_above_8!(dst);
	let src = mask_out_above_8!(src);

	let res = dst + src;
	// m68ki_cpu.n_flag = (res);
	core.n_flag = res;
	// m68ki_cpu.v_flag = ((src^res) & (dst^res));
	core.v_flag = (src ^ res) & (dst ^ res);
	// m68ki_cpu.x_flag = m68ki_cpu.c_flag = (res);
	core.c_flag = res;
	core.x_flag = res;
	// m68ki_cpu.not_z_flag = ((res) & 0xff);
	let res8 = mask_out_above_8!(res);
	core.not_z_flag = res8;
	res8
}
macro_rules! add_8_er {
    ($name:ident, $src:ident) => (
    	pub fn $name(core: &mut Core) {
			let dst = operator::dx(core);
			let src = operator::$src(core);
			let res = add_8_common(core, dst, src);
			dx!(core) = mask_out_below_8!(dst) | res;
    	})
}
add_8_er!(add_8_er_d, dy);
add_8_er!(add_8_er_ai, ay_ai_8);
add_8_er!(add_8_er_pi, ay_pi_8);
add_8_er!(add_8_er_pd, ay_pd_8);
add_8_er!(add_8_er_di, ay_di_8);
add_8_er!(add_8_er_ix, ay_ix_8);
add_8_er!(add_8_er_aw, aw_8);
add_8_er!(add_8_er_al, al_8);
add_8_er!(add_8_er_pcdi, pcdi_8);
add_8_er!(add_8_er_pcix, pcix_8);
add_8_er!(add_8_er_imm, imm_8);

use super::Handler;
#[allow(dead_code)]
struct OpcodeHandler {
	mask: u32,
	matching: u32,
	name: String,
	handler: Handler
}

use super::InstructionSet;
macro_rules! op_entry {
    ($mask:expr, $matching:expr, $handler:ident) => (OpcodeHandler { mask: $mask, matching: $matching, handler: $handler, name: stringify!($handler).to_string() })
}
pub const MASK_OUT_X_Y: u32 = 0b1111000111111000; // masks out X and Y register bits (????xxx??????yyy)
pub const MASK_OUT_X: u32 = 0b1111000111111111; // masks out X register bits (????xxx?????????)
pub const OP_ABCD_8_RR: u32 = 0xc100;
pub const OP_ABCD_8_MM: u32 = 0xc108;
pub const OP_ADD_8_ER_D: u32 = 0xd000;
pub const OP_ADD_8_ER_AI: u32 = 0xd010;
pub const OP_ADD_8_ER_PI: u32 = 0xd018;
pub const OP_ADD_8_ER_PD: u32 = 0xd020;
pub const OP_ADD_8_ER_DI: u32 = 0xd028;
pub const OP_ADD_8_ER_IX: u32 = 0xd030;
pub const OP_ADD_8_ER_AW: u32 = 0xd038;
pub const OP_ADD_8_ER_AL: u32 = 0xd039;
pub const OP_ADD_8_ER_PCDI: u32 = 0xd03a;
pub const OP_ADD_8_ER_PCIX: u32 = 0xd03b;
pub const OP_ADD_8_ER_IMM: u32 = 0xd03c;

pub fn instruction_set() -> InstructionSet {
	// Covers all possible IR values (64k entries)
	let mut handler: InstructionSet = Vec::with_capacity(0x10000);
	for _ in 0..0x10000 { handler.push(illegal); }
	//let handler = [illegal].iter().cycle().take(0x10000).collect::<InstructionSet>();
	// (0..0x10000).map(|_| illegal).collect::<InstructionSet>();
	// the optable contains opcode mask, matching mask and the corresponding handler + name
	let optable = vec![
		op_entry!(MASK_OUT_X_Y, OP_ABCD_8_RR, abcd_8_rr),
		op_entry!(MASK_OUT_X_Y, OP_ABCD_8_MM, abcd_8_mm),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_D, add_8_er_d),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_AI, add_8_er_ai),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_PI, add_8_er_pi),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_PD, add_8_er_pd),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_DI, add_8_er_di),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_IX, add_8_er_ix),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_AW, add_8_er_aw),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_AL, add_8_er_al),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_PCDI, add_8_er_pcdi),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_PCIX, add_8_er_pcix),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_IMM, add_8_er_imm),
	];
	for op in optable {
		for opcode in 0..0x10000 {
			if (opcode & op.mask) == op.matching {
				// println!("{:16b}: {}", opcode, op.name);
				handler[opcode as usize] = op.handler;
			}
		}
	}
	handler
}

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

	#[test]
	fn low_nibble() {
		assert_eq!(0x0a, low_nibble!(0xba));
	}
	#[test]
	fn high_nibble() {
		assert_eq!(0xb0, high_nibble!(0xba));
	}
	#[test]
	fn mask_out_below_8() {
		assert_eq!(0x2bcdef00, mask_out_below_8!(0x2bcdef73));
	}
	#[test]
	fn mask_out_above_8() {
		assert_eq!(0xf1, mask_out_above_8!(0x2bcdeff1));
	}
	#[test]
	fn dx_and_dy() {
		let mut core = Core::new(0x40);
		core.dar[0] = 0x00;
		core.dar[1] = 0x11;
		core.dar[2] = 0x22;
		core.dar[3] = 0x33;
		core.dar[4] = 0x44;
		core.dar[5] = 0x55;
		core.dar[6] = 0x66;
		core.dar[7] = 0x77;

		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		assert_eq!(0x22, dy!(core));
		assert_eq!(0x44, dx!(core));

		core.ir = 0b1111_1011_1111_1110; // X=5, Y=6
		assert_eq!(0x66, dy!(core));
		assert_eq!(0x55, dx!(core));
	}
}
<commit_msg>Add 16-bit mask-outs<commit_after>#![macro_use]
use super::Core;
macro_rules! ir_dx {
	($e:ident) => (($e.ir >> 9 & 7) as usize);
}
macro_rules! ir_dy {
	($e:ident) => (($e.ir & 7) as usize);
}
macro_rules! ir_ax {
	($e:ident) => (8+($e.ir >> 9 & 7) as usize);
}
macro_rules! ir_ay {
	($e:ident) => (8+($e.ir & 7) as usize);
}
macro_rules! dx {
	($e:ident) => ($e.dar[ir_dx!($e)]);
}
macro_rules! dy {
	($e:ident) => ($e.dar[ir_dy!($e)]);
}
macro_rules! ax {
	($e:ident) => ($e.dar[ir_ax!($e)]);
}
macro_rules! ay {
	($e:ident) => ($e.dar[ir_ay!($e)]);
}
macro_rules! mask_out_above_8 {
	($e:expr) => ($e & 0xff)
}
macro_rules! mask_out_below_8 {
	($e:expr) => ($e & !0xff)
}
macro_rules! mask_out_above_16 {
	($e:expr) => ($e & 0xffff)
}
macro_rules! mask_out_below_16 {
	($e:expr) => ($e & !0xffff)
}
macro_rules! low_nibble {
	($e:expr) => ($e & 0x0f);
}
macro_rules! high_nibble {
	($e:expr) => ($e & 0xf0);
}
macro_rules! true1 {
	($e:expr) => (if $e {1} else {0})
}
macro_rules! not1 {
	($e:expr) => (true1!($e == 0))
}

pub mod fake {
	use super::super::Core;

	pub fn set_d0(core: &mut Core) {
		core.dar[0] = 0xabcd;
	}

	pub fn set_d1(core: &mut Core) {
		core.dar[1] = 0xbcde;
	}

	pub fn set_dx(core: &mut Core) {
		dx!(core) = 0xcdef;
	}

	use super::super::InstructionSet;
	use super::illegal;
	const SET_DX_0: usize = 0b0100_0000_0000_0000;

	pub fn instruction_set() -> InstructionSet {
		// Covers all possible IR values (64k entries)
		let mut handler: InstructionSet = Vec::with_capacity(0x10000);
		for _ in 0..0x10000 { handler.push(illegal); }
		handler[0xA] = set_d0;
		handler[0xB] = set_d1;
		for i in 0..8 {
			let opcode = SET_DX_0 | (i << 9);
			// println!("{:x}", opcode);
			handler[opcode] = set_dx;
		}
		handler
	}
}

pub fn illegal(core: &mut Core) {
	panic!("Illegal instruction {:04x} at {:08x}", core.ir, core.pc-2);
}

use std::num::Wrapping;
use super::operator;

// All instructions are ported from https://github.com/kstenerud/Musashi
pub fn abcd_8_common(core: &mut Core, dst: u32, src: u32) -> u32 {
	// unsigned int res = ((src) & 0x0f) + ((dst) & 0x0f) + ((m68ki_cpu.x_flag>>8)&1);
	let mut res = low_nibble!(src) + low_nibble!(dst) + core.x_flag_as_1();

	// m68ki_cpu.v_flag = ~res;
	core.v_flag = !res;

	// if(res > 9)
	//  res += 6;
	if res > 9 {
		res += 6;
	}
	// res += ((src) & 0xf0) + ((dst) & 0xf0);
	res += high_nibble!(src) + high_nibble!(dst);
	// m68ki_cpu.x_flag = m68ki_cpu.c_flag = (res > 0x99) << 8;
	core.c_flag = true1!(res > 0x99) << 8;
	core.x_flag = core.c_flag;

	if core.c_flag > 0 {
		res = (Wrapping(res) - Wrapping(0xa0)).0;
	}

	// m68ki_cpu.v_flag &= res;
	// m68ki_cpu.n_flag = (res);
	core.v_flag &= res;
	core.n_flag = res;

	// res = ((res) & 0xff);
	// m68ki_cpu.not_z_flag |= res;
	res = mask_out_above_8!(res);
	core.not_z_flag |= res;
	res
}
pub fn abcd_8_rr(core: &mut Core) {
	let dst = operator::dx(core);
	let src = operator::dy(core);
	let res = abcd_8_common(core, dst, src);
	dx!(core) = mask_out_below_8!(dst) | res;
}
pub fn abcd_8_mm(core: &mut Core) {
	let src = operator::ay_pd_8(core);
	let (dst, ea) = operator::ax_pd_8(core);
	let res = abcd_8_common(core, dst, src);
	core.write_data_byte(ea, res);
}

fn add_8_common(core: &mut Core, dst: u32, src: u32) -> u32 {
	let dst = mask_out_above_8!(dst);
	let src = mask_out_above_8!(src);

	let res = dst + src;
	// m68ki_cpu.n_flag = (res);
	core.n_flag = res;
	// m68ki_cpu.v_flag = ((src^res) & (dst^res));
	core.v_flag = (src ^ res) & (dst ^ res);
	// m68ki_cpu.x_flag = m68ki_cpu.c_flag = (res);
	core.c_flag = res;
	core.x_flag = res;
	// m68ki_cpu.not_z_flag = ((res) & 0xff);
	let res8 = mask_out_above_8!(res);
	core.not_z_flag = res8;
	res8
}
macro_rules! add_8_er {
    ($name:ident, $src:ident) => (
    	pub fn $name(core: &mut Core) {
			let dst = operator::dx(core);
			let src = operator::$src(core);
			let res = add_8_common(core, dst, src);
			dx!(core) = mask_out_below_8!(dst) | res;
    	})
}
add_8_er!(add_8_er_d, dy);
add_8_er!(add_8_er_ai, ay_ai_8);
add_8_er!(add_8_er_pi, ay_pi_8);
add_8_er!(add_8_er_pd, ay_pd_8);
add_8_er!(add_8_er_di, ay_di_8);
add_8_er!(add_8_er_ix, ay_ix_8);
add_8_er!(add_8_er_aw, aw_8);
add_8_er!(add_8_er_al, al_8);
add_8_er!(add_8_er_pcdi, pcdi_8);
add_8_er!(add_8_er_pcix, pcix_8);
add_8_er!(add_8_er_imm, imm_8);

use super::Handler;
#[allow(dead_code)]
struct OpcodeHandler {
	mask: u32,
	matching: u32,
	name: String,
	handler: Handler
}

use super::InstructionSet;
macro_rules! op_entry {
    ($mask:expr, $matching:expr, $handler:ident) => (OpcodeHandler { mask: $mask, matching: $matching, handler: $handler, name: stringify!($handler).to_string() })
}
pub const MASK_OUT_X_Y: u32 = 0b1111000111111000; // masks out X and Y register bits (????xxx??????yyy)
pub const MASK_OUT_X: u32 = 0b1111000111111111; // masks out X register bits (????xxx?????????)
pub const OP_ABCD_8_RR: u32 = 0xc100;
pub const OP_ABCD_8_MM: u32 = 0xc108;
pub const OP_ADD_8_ER_D: u32 = 0xd000;
pub const OP_ADD_8_ER_AI: u32 = 0xd010;
pub const OP_ADD_8_ER_PI: u32 = 0xd018;
pub const OP_ADD_8_ER_PD: u32 = 0xd020;
pub const OP_ADD_8_ER_DI: u32 = 0xd028;
pub const OP_ADD_8_ER_IX: u32 = 0xd030;
pub const OP_ADD_8_ER_AW: u32 = 0xd038;
pub const OP_ADD_8_ER_AL: u32 = 0xd039;
pub const OP_ADD_8_ER_PCDI: u32 = 0xd03a;
pub const OP_ADD_8_ER_PCIX: u32 = 0xd03b;
pub const OP_ADD_8_ER_IMM: u32 = 0xd03c;

pub fn instruction_set() -> InstructionSet {
	// Covers all possible IR values (64k entries)
	let mut handler: InstructionSet = Vec::with_capacity(0x10000);
	for _ in 0..0x10000 { handler.push(illegal); }
	//let handler = [illegal].iter().cycle().take(0x10000).collect::<InstructionSet>();
	// (0..0x10000).map(|_| illegal).collect::<InstructionSet>();
	// the optable contains opcode mask, matching mask and the corresponding handler + name
	let optable = vec![
		op_entry!(MASK_OUT_X_Y, OP_ABCD_8_RR, abcd_8_rr),
		op_entry!(MASK_OUT_X_Y, OP_ABCD_8_MM, abcd_8_mm),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_D, add_8_er_d),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_AI, add_8_er_ai),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_PI, add_8_er_pi),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_PD, add_8_er_pd),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_DI, add_8_er_di),
		op_entry!(MASK_OUT_X_Y, OP_ADD_8_ER_IX, add_8_er_ix),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_AW, add_8_er_aw),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_AL, add_8_er_al),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_PCDI, add_8_er_pcdi),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_PCIX, add_8_er_pcix),
		op_entry!(MASK_OUT_X, OP_ADD_8_ER_IMM, add_8_er_imm),
	];
	for op in optable {
		for opcode in 0..0x10000 {
			if (opcode & op.mask) == op.matching {
				// println!("{:16b}: {}", opcode, op.name);
				handler[opcode as usize] = op.handler;
			}
		}
	}
	handler
}

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

	#[test]
	fn low_nibble() {
		assert_eq!(0x0a, low_nibble!(0xba));
	}
	#[test]
	fn high_nibble() {
		assert_eq!(0xb0, high_nibble!(0xba));
	}
	#[test]
	fn mask_out_below_8() {
		assert_eq!(0x2bcdef00, mask_out_below_8!(0x2bcdef73));
	}
	#[test]
	fn mask_out_above_8() {
		assert_eq!(0xf1, mask_out_above_8!(0x2bcdeff1));
	}
	#[test]
	fn dx_and_dy() {
		let mut core = Core::new(0x40);
		core.dar[0] = 0x00;
		core.dar[1] = 0x11;
		core.dar[2] = 0x22;
		core.dar[3] = 0x33;
		core.dar[4] = 0x44;
		core.dar[5] = 0x55;
		core.dar[6] = 0x66;
		core.dar[7] = 0x77;

		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		assert_eq!(0x22, dy!(core));
		assert_eq!(0x44, dx!(core));

		core.ir = 0b1111_1011_1111_1110; // X=5, Y=6
		assert_eq!(0x66, dy!(core));
		assert_eq!(0x55, dx!(core));
	}
}
<|endoftext|>