<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use lib::*;

macro_rules! int_to_int {
    ($dst:ident, $n:ident) => {
        if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
            Some($n as $dst)
        } else {
            None
        }
    };
}

macro_rules! int_to_uint {
    ($dst:ident, $n:ident) => {
        if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
            Some($n as $dst)
        } else {
            None
        }
    };
}

macro_rules! uint_to {
    ($dst:ident, $n:ident) => {
        if $n as u64 <= $dst::max_value() as u64 {
            Some($n as $dst)
        } else {
            None
        }
    };
}

pub trait FromPrimitive: Sized {
    fn from_isize(n: isize) -> Option<Self>;
    fn from_i8(n: i8) -> Option<Self>;
    fn from_i16(n: i16) -> Option<Self>;
    fn from_i32(n: i32) -> Option<Self>;
    fn from_i64(n: i64) -> Option<Self>;
    fn from_usize(n: usize) -> Option<Self>;
    fn from_u8(n: u8) -> Option<Self>;
    fn from_u16(n: u16) -> Option<Self>;
    fn from_u32(n: u32) -> Option<Self>;
    fn from_u64(n: u64) -> Option<Self>;
}

macro_rules! impl_from_primitive_for_int {
    ($t:ident) => {
        impl FromPrimitive for $t {
            #[inline]
            fn from_isize(n: isize) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i8(n: i8) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i16(n: i16) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i32(n: i32) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i64(n: i64) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_usize(n: usize) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u8(n: u8) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u16(n: u16) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u32(n: u32) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u64(n: u64) -> Option<Self> {
                uint_to!($t, n)
            }
        }
    };
}

macro_rules! impl_from_primitive_for_uint {
    ($t:ident) => {
        impl FromPrimitive for $t {
            #[inline]
            fn from_isize(n: isize) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i8(n: i8) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i16(n: i16) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i32(n: i32) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i64(n: i64) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_usize(n: usize) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u8(n: u8) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u16(n: u16) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u32(n: u32) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u64(n: u64) -> Option<Self> {
                uint_to!($t, n)
            }
        }
    };
}

macro_rules! impl_from_primitive_for_float {
    ($t:ident) => {
        impl FromPrimitive for $t {
            #[inline]
            fn from_isize(n: isize) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i8(n: i8) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i16(n: i16) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i32(n: i32) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i64(n: i64) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_usize(n: usize) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u8(n: u8) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u16(n: u16) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u32(n: u32) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u64(n: u64) -> Option<Self> {
                Some(n as Self)
            }
        }
    };
}

impl_from_primitive_for_int!(isize);
impl_from_primitive_for_int!(i8);
impl_from_primitive_for_int!(i16);
impl_from_primitive_for_int!(i32);
impl_from_primitive_for_int!(i64);
impl_from_primitive_for_uint!(usize);
impl_from_primitive_for_uint!(u8);
impl_from_primitive_for_uint!(u16);
impl_from_primitive_for_uint!(u32);
impl_from_primitive_for_uint!(u64);
impl_from_primitive_for_float!(f32);
impl_from_primitive_for_float!(f64);
<commit_msg>Remove unused methods on FromPrimitive trait<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use lib::*;

macro_rules! int_to_int {
    ($dst:ident, $n:ident) => {
        if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
            Some($n as $dst)
        } else {
            None
        }
    };
}

macro_rules! int_to_uint {
    ($dst:ident, $n:ident) => {
        if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
            Some($n as $dst)
        } else {
            None
        }
    };
}

macro_rules! uint_to {
    ($dst:ident, $n:ident) => {
        if $n as u64 <= $dst::max_value() as u64 {
            Some($n as $dst)
        } else {
            None
        }
    };
}

pub trait FromPrimitive: Sized {
    fn from_i8(n: i8) -> Option<Self>;
    fn from_i16(n: i16) -> Option<Self>;
    fn from_i32(n: i32) -> Option<Self>;
    fn from_i64(n: i64) -> Option<Self>;
    fn from_u8(n: u8) -> Option<Self>;
    fn from_u16(n: u16) -> Option<Self>;
    fn from_u32(n: u32) -> Option<Self>;
    fn from_u64(n: u64) -> Option<Self>;
}

macro_rules! impl_from_primitive_for_int {
    ($t:ident) => {
        impl FromPrimitive for $t {
            #[inline]
            fn from_i8(n: i8) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i16(n: i16) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i32(n: i32) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_i64(n: i64) -> Option<Self> {
                int_to_int!($t, n)
            }
            #[inline]
            fn from_u8(n: u8) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u16(n: u16) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u32(n: u32) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u64(n: u64) -> Option<Self> {
                uint_to!($t, n)
            }
        }
    };
}

macro_rules! impl_from_primitive_for_uint {
    ($t:ident) => {
        impl FromPrimitive for $t {
            #[inline]
            fn from_i8(n: i8) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i16(n: i16) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i32(n: i32) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_i64(n: i64) -> Option<Self> {
                int_to_uint!($t, n)
            }
            #[inline]
            fn from_u8(n: u8) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u16(n: u16) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u32(n: u32) -> Option<Self> {
                uint_to!($t, n)
            }
            #[inline]
            fn from_u64(n: u64) -> Option<Self> {
                uint_to!($t, n)
            }
        }
    };
}

macro_rules! impl_from_primitive_for_float {
    ($t:ident) => {
        impl FromPrimitive for $t {
            #[inline]
            fn from_i8(n: i8) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i16(n: i16) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i32(n: i32) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_i64(n: i64) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u8(n: u8) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u16(n: u16) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u32(n: u32) -> Option<Self> {
                Some(n as Self)
            }
            #[inline]
            fn from_u64(n: u64) -> Option<Self> {
                Some(n as Self)
            }
        }
    };
}

impl_from_primitive_for_int!(isize);
impl_from_primitive_for_int!(i8);
impl_from_primitive_for_int!(i16);
impl_from_primitive_for_int!(i32);
impl_from_primitive_for_int!(i64);
impl_from_primitive_for_uint!(usize);
impl_from_primitive_for_uint!(u8);
impl_from_primitive_for_uint!(u16);
impl_from_primitive_for_uint!(u32);
impl_from_primitive_for_uint!(u64);
impl_from_primitive_for_float!(f32);
impl_from_primitive_for_float!(f64);
<|endoftext|>


<commit_before>
use num::*;
use mat::Mat4;
use vec::Vec3;
use std::ops::*;

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Quaternion<T: Num + Float + Copy> {
    pub x: T,
    pub y: T,
    pub w: T,
    pub z: T,
}

impl<T: Num + Float + Copy> Default for Quaternion<T> {
    fn default() -> Quaternion<T> {
        Quaternion::new()
    }
}

impl<T: Num + Float + Copy> Quaternion<T> {
    /// Creates a new identity quaternion
    pub fn new() -> Quaternion<T> {
        Quaternion {
            x: T::zero(),
            y: T::zero(),
            z: T::zero(),
            w: T::one(),
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// given axis. This function normalizes the axis, but if the axis is `(0, 0, 0)` the quaternion
    /// will have its `x`, `y` and `z` fields set to 0.
    pub fn rotation(angle: T, axis: Vec3<T>) -> Quaternion<T> {
        let axis = axis.normalize();
        let angle = angle / (T::one() + T::one());
        let (sin, cos) = angle.sin_cos();
        Quaternion {
            x: axis.x*sin,
            y: axis.y*sin,
            z: axis.z*sin,
            w: cos,
        }
    }

    /// Calculates the length of this quaternion, raised to the power of two. Note that this is
    /// cheaper than computing the actual length.
    pub fn len_sqr(&self) -> T {
        self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w
    }

    /// Calculates the length of this quaternion.
    pub fn len(&self) -> T {
        (self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w).sqrt()
    }

    /// Normalizes this quaternion, returning a new quaternion with length 1.
    pub fn normalize(&self) -> Quaternion<T> {
        *self / self.len()
    }

    /// Calculates the dot (inner) product of the two given quaternions.
    pub fn dot(a: Quaternion<T>, b: Quaternion<T>) -> T {
        a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
    }

    /// Calculates the angle between the two given quaternions
    pub fn angle_between(a: Quaternion<T>, b: Quaternion<T>) -> T {
        Quaternion::dot(a, b).acos()
    }

    /// Interpolates linearly between the two given quaternions. This works well as long as the
    /// quaternions are not to different. `t` should be in the range `0..1`.
    ///
    /// nlerp stands for normalized linear interpolation.
    pub fn nlerp(a: Quaternion<T>, b: Quaternion<T>, t: T) -> Quaternion<T> {
        (a*(T::one() - t) + b*t).normalize()
    }
}

// Quaternion vector multiplication
impl<T: Num + Float + Copy> Mul<Vec3<T>> for Quaternion<T> {
    type Output = Vec3<T>;
    fn mul(self, vec: Vec3<T>) -> Vec3<T> {
        let one = T::one();
        let two = one + one;

        let a11 = one - two*self.y*self.y - two*self.z*self.z;
        let a12 = two*self.x*self.y - two*self.z*self.w;
        let a13 = two*self.x*self.z + two*self.y*self.w;

        let a21 = two*self.x*self.y + two*self.w*self.z;
        let a22 = one - two*self.x*self.x - two*self.z*self.z;
        let a23 = two*self.y*self.z - two*self.w*self.x;

        let a31 = two*self.x*self.z - two*self.w*self.y;
        let a32 = two*self.y*self.z + two*self.w*self.x;
        let a33 = one - two*self.x*self.x - two*self.y*self.y;

        Vec3 {
            x: vec.x*a11 + vec.y*a12 + vec.z*a13,
            y: vec.x*a21 + vec.y*a22 + vec.z*a23,
            z: vec.x*a31 + vec.y*a32 + vec.z*a33,
        }
    }
}

// Quaternion quaternion multiplication
impl<T: Num + Float + Copy> Mul for Quaternion<T> {
    type Output = Self;
    fn mul(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y,
            y: self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z,
            z: self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x,
            w: self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign for Quaternion<T> {
    fn mul_assign(&mut self, other: Quaternion<T>) {
        let x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y;
        let y = self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z;
        let z = self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x;
        let w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z;
        self.x = x;
        self.y = y;
        self.z = z;
        self.w = w;
    }
}

// Quaternion quaternion addition
impl<T: Num + Float + Copy> Add for Quaternion<T> {
    type Output = Self;
    fn add(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}

// Quaternion scalar multiplication
impl<T: Num + Float + Copy> Mul<T> for Quaternion<T> {
    type Output = Self;
    fn mul(self, scalar: T) -> Self {
        Quaternion {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
            w: self.w * scalar,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign<T> for Quaternion<T> {
    fn mul_assign(&mut self, scalar: T) {
        self.x = self.x * scalar;
        self.y = self.y * scalar;
        self.z = self.z * scalar;
        self.w = self.w * scalar;
    }
}
impl<T: Num + Float + Copy> Div<T> for Quaternion<T> {
    type Output = Self;
    fn div(self, scalar: T) -> Self {
        Quaternion {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
            w: self.w / scalar,
        }
    }
}
impl<T: Num + Float + Copy> DivAssign<T> for Quaternion<T> {
    fn div_assign(&mut self, scalar: T) {
        self.x = self.x / scalar;
        self.y = self.y / scalar;
        self.z = self.z / scalar;
        self.w = self.w / scalar;
    }
}

impl<T: Num + Float + Copy> From<Quaternion<T>> for Mat4<T> {
    fn from(quat: Quaternion<T>) -> Mat4<T> {
        Mat4::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::*;
    use {Mat4, Vec4};

    #[test]
    fn identity() {
        let identity = Quaternion::<f32>::new();
        assert_eq!(identity, identity*identity);
        assert_eq!(identity, identity*identity*identity);
    }

    #[test]
    fn matrix_rotation() {
        let quat = Quaternion::<f32>::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0));
        let mat: Mat4<f32> = quat.into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);
        let b = Vec4::new(0.0, 0.0, 1.0, 1.0);

        let diff = (mat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn matrix_rotation_reverse() {
        let mat_a: Mat4<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let mat_b: Mat4<f32> = Quaternion::rotation(-f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);

        let diff = (mat_a*mat_b*a - a).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn quaternion_rotation() {
        let quat: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec3::new(0.0, 1.0, 0.0);
        let b = Vec3::new(0.0, 0.0, 1.0);

        let diff = (quat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn angle_between() {
        let a: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(0.0, 1.0, 0.0)).into();

        let diff = Quaternion::angle_between(a, b) - f32::consts::PI/2.0;
        assert!(diff < 0.001);
    }

    #[test]
    fn nlerp() {
        let a = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b = Quaternion::new();

        let c = Quaternion::nlerp(a, b, 0.5);
        let expected = Quaternion::rotation(f32::consts::PI/4.0, Vec3::new(1.0, 0.0, 0.0));

        let diff = Quaternion::angle_between(c, expected);
        assert!(diff < 0.001);
    }
}
<commit_msg>Fixed quaternion nlerp for > 180° angles<commit_after>
use num::*;
use mat::Mat4;
use vec::Vec3;
use std::ops::*;

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Quaternion<T: Num + Float + Copy> {
    pub x: T,
    pub y: T,
    pub w: T,
    pub z: T,
}

impl<T: Num + Float + Copy> Default for Quaternion<T> {
    fn default() -> Quaternion<T> {
        Quaternion::new()
    }
}

impl<T: Num + Float + Copy> Quaternion<T> {
    /// Creates a new identity quaternion
    pub fn new() -> Quaternion<T> {
        Quaternion {
            x: T::zero(),
            y: T::zero(),
            z: T::zero(),
            w: T::one(),
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// given axis. This function normalizes the axis, but if the axis is `(0, 0, 0)` the quaternion
    /// will have its `x`, `y` and `z` fields set to 0.
    pub fn rotation(angle: T, axis: Vec3<T>) -> Quaternion<T> {
        let axis = axis.normalize();
        let angle = angle / (T::one() + T::one());
        let (sin, cos) = angle.sin_cos();
        Quaternion {
            x: axis.x*sin,
            y: axis.y*sin,
            z: axis.z*sin,
            w: cos,
        }
    }

    /// Calculates the length of this quaternion, raised to the power of two. Note that this is
    /// cheaper than computing the actual length.
    pub fn len_sqr(&self) -> T {
        self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w
    }

    /// Calculates the length of this quaternion.
    pub fn len(&self) -> T {
        (self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w).sqrt()
    }

    /// Normalizes this quaternion, returning a new quaternion with length 1.
    pub fn normalize(&self) -> Quaternion<T> {
        *self / self.len()
    }

    /// Calculates the dot (inner) product of the two given quaternions.
    pub fn dot(a: Quaternion<T>, b: Quaternion<T>) -> T {
        a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
    }

    /// Calculates the angle between the two given quaternions
    pub fn angle_between(a: Quaternion<T>, b: Quaternion<T>) -> T {
        Quaternion::dot(a, b).acos()
    }

    /// Interpolates linearly between the two given quaternions. This works well as long as the
    /// quaternions are not to different. `t` should be in the range `0..1`.
    ///
    /// nlerp stands for normalized linear interpolation.
    pub fn nlerp(a: Quaternion<T>, b: Quaternion<T>, t: T) -> Quaternion<T> {
        if Quaternion::dot(a, b) < T::zero() {
            (a*(T::one() - t) - b*t).normalize()
        } else {
            (a*(T::one() - t) + b*t).normalize()
        }
    }
}

// Quaternion vector multiplication
impl<T: Num + Float + Copy> Mul<Vec3<T>> for Quaternion<T> {
    type Output = Vec3<T>;
    fn mul(self, vec: Vec3<T>) -> Vec3<T> {
        let one = T::one();
        let two = one + one;

        let a11 = one - two*self.y*self.y - two*self.z*self.z;
        let a12 = two*self.x*self.y - two*self.z*self.w;
        let a13 = two*self.x*self.z + two*self.y*self.w;

        let a21 = two*self.x*self.y + two*self.w*self.z;
        let a22 = one - two*self.x*self.x - two*self.z*self.z;
        let a23 = two*self.y*self.z - two*self.w*self.x;

        let a31 = two*self.x*self.z - two*self.w*self.y;
        let a32 = two*self.y*self.z + two*self.w*self.x;
        let a33 = one - two*self.x*self.x - two*self.y*self.y;

        Vec3 {
            x: vec.x*a11 + vec.y*a12 + vec.z*a13,
            y: vec.x*a21 + vec.y*a22 + vec.z*a23,
            z: vec.x*a31 + vec.y*a32 + vec.z*a33,
        }
    }
}

// Quaternion quaternion multiplication
impl<T: Num + Float + Copy> Mul for Quaternion<T> {
    type Output = Self;
    fn mul(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y,
            y: self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z,
            z: self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x,
            w: self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign for Quaternion<T> {
    fn mul_assign(&mut self, other: Quaternion<T>) {
        let x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y;
        let y = self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z;
        let z = self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x;
        let w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z;
        self.x = x;
        self.y = y;
        self.z = z;
        self.w = w;
    }
}

// Quaternion quaternion addition
impl<T: Num + Float + Copy> Add for Quaternion<T> {
    type Output = Self;
    fn add(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}
impl<T: Num + Float + Copy> Sub for Quaternion<T> {
    type Output = Self;
    fn sub(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        }
    }
}

// Quaternion scalar multiplication
impl<T: Num + Float + Copy> Mul<T> for Quaternion<T> {
    type Output = Self;
    fn mul(self, scalar: T) -> Self {
        Quaternion {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
            w: self.w * scalar,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign<T> for Quaternion<T> {
    fn mul_assign(&mut self, scalar: T) {
        self.x = self.x * scalar;
        self.y = self.y * scalar;
        self.z = self.z * scalar;
        self.w = self.w * scalar;
    }
}
impl<T: Num + Float + Copy> Div<T> for Quaternion<T> {
    type Output = Self;
    fn div(self, scalar: T) -> Self {
        Quaternion {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
            w: self.w / scalar,
        }
    }
}
impl<T: Num + Float + Copy> DivAssign<T> for Quaternion<T> {
    fn div_assign(&mut self, scalar: T) {
        self.x = self.x / scalar;
        self.y = self.y / scalar;
        self.z = self.z / scalar;
        self.w = self.w / scalar;
    }
}

impl<T: Num + Float + Copy> From<Quaternion<T>> for Mat4<T> {
    fn from(quat: Quaternion<T>) -> Mat4<T> {
        Mat4::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::*;
    use {Mat4, Vec4};

    #[test]
    fn identity() {
        let identity = Quaternion::<f32>::new();
        assert_eq!(identity, identity*identity);
        assert_eq!(identity, identity*identity*identity);
    }

    #[test]
    fn matrix_rotation() {
        let quat = Quaternion::<f32>::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0));
        let mat: Mat4<f32> = quat.into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);
        let b = Vec4::new(0.0, 0.0, 1.0, 1.0);

        let diff = (mat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn matrix_rotation_reverse() {
        let mat_a: Mat4<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let mat_b: Mat4<f32> = Quaternion::rotation(-f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);

        let diff = (mat_a*mat_b*a - a).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn quaternion_rotation() {
        let quat: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec3::new(0.0, 1.0, 0.0);
        let b = Vec3::new(0.0, 0.0, 1.0);

        let diff = (quat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn angle_between() {
        let a: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(0.0, 1.0, 0.0)).into();

        let diff = Quaternion::angle_between(a, b) - f32::consts::PI/2.0;
        assert!(diff < 0.001);
    }

    #[test]
    fn nlerp() {
        let a = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b = Quaternion::new();

        let c = Quaternion::nlerp(a, b, 0.5);
        let expected = Quaternion::rotation(f32::consts::PI/4.0, Vec3::new(1.0, 0.0, 0.0));

        let diff = Quaternion::angle_between(c, expected);
        assert!(diff < 0.001);
    }
}
<|endoftext|>


<commit_before>//! This zero-delay feedback filter is based on a 4-stage transistor ladder filter.
//! It follows the following equations:
//! x = input - tanh(self.res * self.vout[3])
//! vout[0] = self.params.g.get() * (tanh(x) - tanh(self.vout[0])) + self.s[0]
//! vout[1] = self.params.g.get() * (tanh(self.vout[0]) - tanh(self.vout[1])) + self.s[1]
//! vout[0] = self.params.g.get() * (tanh(self.vout[1]) - tanh(self.vout[2])) + self.s[2]
//! vout[0] = self.params.g.get() * (tanh(self.vout[2]) - tanh(self.vout[3])) + self.s[3]
//! since we can't easily solve a nonlinear equation,
//! Mystran's fixed-pivot method is used to approximate the tanh() parts.
//! Quality can be improved a lot by oversampling a bit.
//! Feedback is clipped independently of the input, so it doesn't disappear at high gains.

#[macro_use]
extern crate vst;
use std::f32::consts::PI;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use vst::buffer::AudioBuffer;
use vst::plugin::{Category, Info, Plugin, PluginParameters};
use vst::util::AtomicFloat;

// this is a 4-pole filter with resonance, which is why there's 4 states and vouts
#[derive(Clone)]
struct LadderFilter {
    // Store a handle to the plugin's parameter object.
    params: Arc<LadderParameters>,
    // the output of the different filter stages
    vout: [f32; 4],
    // s is the "state" parameter. In an IIR it would be the last value from the filter
    // In this we find it by trapezoidal integration to avoid the unit delay
    s: [f32; 4],
}
struct LadderParameters {
    // the "cutoff" parameter. Determines how heavy filtering is
    cutoff: AtomicFloat,
    g: AtomicFloat,
    // needed to calculate cutoff.
    sample_rate: AtomicFloat,
    // makes a peak at cutoff
    res: AtomicFloat,
    // used to choose where we want our output to be
    poles: AtomicUsize,
    // a drive parameter. Just used to increase the volume, which results in heavier distortion
    drive: AtomicFloat,
}
impl Default for LadderParameters {
    fn default() -> LadderParameters {
        LadderParameters {
            cutoff: AtomicFloat::new(1000.),
            res: AtomicFloat::new(2.),
            poles: AtomicUsize::new(3),
            drive: AtomicFloat::new(0.),
            sample_rate: AtomicFloat::new(44100.),
            g: AtomicFloat::new(0.07135868087),
        }
    }
}
// member methods for the struct
impl LadderFilter {
    // the state needs to be updated after each process. Found by trapezoidal integration
    fn update_state(&mut self) {
        self.s[0] = 2. * self.vout[0] - self.s[0];
        self.s[1] = 2. * self.vout[1] - self.s[1];
        self.s[2] = 2. * self.vout[2] - self.s[2];
        self.s[3] = 2. * self.vout[3] - self.s[3];
    }
    // performs a complete filter process (mystran's method)
    fn tick_pivotal(&mut self, input: f32) {
        if self.params.drive.get() > 0. {
            self.run_ladder_nonlinear(input * (self.params.drive.get() + 0.7));
        } else {
            //
            self.run_ladder_linear(input);
        }
        self.update_state();
    }
    // nonlinear ladder filter function with distortion.
    fn run_ladder_nonlinear(&mut self, input: f32) {
        let mut a = [1f32; 5];
        let base = [input, self.s[0], self.s[1], self.s[2], self.s[3]];
        // a[n] is the fixed-pivot approximation for tanh()
        for n in 0..base.len() {
            if base[n] != 0. {
                a[n] = base[n].tanh() / base[n];
            } else {
                a[n] = 1.;
            }
        }
        // denominators of solutions of individual stages. Simplifies the math a bit
        let g0 = 1. / (1. + self.params.g.get() * a[1]);
        let g1 = 1. / (1. + self.params.g.get() * a[2]);
        let g2 = 1. / (1. + self.params.g.get() * a[3]);
        let g3 = 1. / (1. + self.params.g.get() * a[4]);
        //  these are just factored out of the feedback solution. Makes the math way easier to read
        let f3 = self.params.g.get() * a[3] * g3;
        let f2 = self.params.g.get() * a[2] * g2 * f3;
        let f1 = self.params.g.get() * a[1] * g1 * f2;
        let f0 = self.params.g.get() * g0 * f1;
        // outputs a 24db filter
        self.vout[3] = (f0 * input * a[0]
            + f1 * g0 * self.s[0]
            + f2 * g1 * self.s[1]
            + f3 * g2 * self.s[2]
            + g3 * self.s[3])
            / (f0 * self.params.res.get() * a[3] + 1.);
        // since we know the feedback, we can solve the remaining outputs:
        self.vout[0] = g0
            * (self.params.g.get()
                * a[1]
                * (input * a[0] - self.params.res.get() * a[3] * self.vout[3])
                + self.s[0]);
        self.vout[1] = g1 * (self.params.g.get() * a[2] * self.vout[0] + self.s[1]);
        self.vout[2] = g2 * (self.params.g.get() * a[3] * self.vout[1] + self.s[2]);
    }
    // linear version without distortion
    pub fn run_ladder_linear(&mut self, input: f32) {
        // denominators of solutions of individual stages. Simplifies the math a bit
        let g0 = 1. / (1. + self.params.g.get());
        let g1 = self.params.g.get() * g0 * g0;
        let g2 = self.params.g.get() * g1 * g0;
        let g3 = self.params.g.get() * g2 * g0;
        // outputs a 24db filter
        self.vout[3] = (g3 * self.params.g.get() * input
            + g0 * self.s[3]
            + g1 * self.s[2]
            + g2 * self.s[1]
            + g3 * self.s[0])
            / (g3 * self.params.g.get() * self.params.res.get() + 1.);
        // since we know the feedback, we can solve the remaining outputs:
        self.vout[0] =
            g0 * (self.params.g.get() * (input - self.params.res.get() * self.vout[3]) + self.s[0]);
        self.vout[1] = g0 * (self.params.g.get() * self.vout[0] + self.s[1]);
        self.vout[2] = g0 * (self.params.g.get() * self.vout[1] + self.s[2]);
    }
}
impl LadderParameters {
    pub fn set_cutoff(&self, value: f32) {
        // cutoff formula gives us a natural feeling cutoff knob that spends more time in the low frequencies
        self.cutoff.set(20000. * (1.8f32.powf(10. * value - 10.)));
        // bilinear transformation for g gives us a very accurate cutoff
        self.g
            .set((PI * self.cutoff.get() / (self.sample_rate.get())).tan());
    }
    pub fn get_poles(&self) -> f32 {
        self.poles.load(Ordering::Relaxed) as f32 + 1.
    }
}
impl PluginParameters for LadderParameters {
    fn get_parameter(&self, index: i32) -> f32 {
        match index {
            0 => self.cutoff.get(),
            1 => self.res.get(),
            2 => self.get_poles(),
            3 => self.drive.get(),
            _ => 0.0,
        }
    }
    fn set_parameter(&self, index: i32, value: f32) {
        match index {
            0 => self.set_cutoff(value),
            1 => self.res.set(value * 4.),
            2 => self
                .poles
                .store(((value * 3.).round()) as usize, Ordering::Relaxed),
            3 => self.drive.set(value * 5.),
            _ => (),
        }
    }

    fn get_parameter_name(&self, index: i32) -> String {
        match index {
            0 => "cutoff".to_string(),
            1 => "resonance".to_string(),
            2 => "filter order".to_string(),
            3 => "drive".to_string(),
            _ => "".to_string(),
        }
    }
    fn get_parameter_label(&self, index: i32) -> String {
        match index {
            0 => "Hz".to_string(),
            1 => "%".to_string(),
            2 => "poles".to_string(),
            3 => "%".to_string(),
            _ => "".to_string(),
        }
    }
    // This is what will display underneath our control.  We can
    // format it into a string that makes the most sense.
    fn get_parameter_text(&self, index: i32) -> String {
        match index {
            0 => format!("{:.0}", self.cutoff.get()),
            1 => format!("{:.3}", self.res.get()),
            2 => format!("{}", self.get_poles()),
            3 => format!("{:.3}", self.drive.get()),
            _ => format!(""),
        }
    }
}

// default values for parameters
impl Default for LadderFilter {
    fn default() -> LadderFilter {
        LadderFilter {
            vout: [0f32; 4],
            s: [0f32; 4],
            params: Arc::new(LadderParameters::default()),
        }
    }
}
impl Plugin for LadderFilter {
    fn set_sample_rate(&mut self, rate: f32) {
        self.params.sample_rate.set(rate);
    }
    fn get_info(&self) -> Info {
        Info {
            name: "LadderFilter".to_string(),
            unique_id: 9263,
            inputs: 1,
            outputs: 1,
            category: Category::Effect,
            parameters: 4,
            ..Default::default()
        }
    }
    fn process(&mut self, buffer: &mut AudioBuffer<f32>) {
        for (input_buffer, output_buffer) in buffer.zip() {
            for (input_sample, output_sample) in input_buffer.iter().zip(output_buffer) {
                self.tick_pivotal(*input_sample);
                // the poles parameter chooses which filter stage we take our output from.
                *output_sample = self.vout[self.params.poles.load(Ordering::Relaxed)];
            }
        }
    }
    fn get_parameter_object(&mut self) -> Arc<dyn PluginParameters> {
        Arc::clone(&self.params) as Arc<dyn PluginParameters>
    }
}
plugin_main!(LadderFilter);
<commit_msg>fixed get_parameter<commit_after>    //! This zero-delay feedback filter is based on a 4-stage transistor ladder filter.
    //! It follows the following equations:
    //! x = input - tanh(self.res * self.vout[3])
    //! vout[0] = self.params.g.get() * (tanh(x) - tanh(self.vout[0])) + self.s[0]
    //! vout[1] = self.params.g.get() * (tanh(self.vout[0]) - tanh(self.vout[1])) + self.s[1]
    //! vout[0] = self.params.g.get() * (tanh(self.vout[1]) - tanh(self.vout[2])) + self.s[2]
    //! vout[0] = self.params.g.get() * (tanh(self.vout[2]) - tanh(self.vout[3])) + self.s[3]
    //! since we can't easily solve a nonlinear equation,
    //! Mystran's fixed-pivot method is used to approximate the tanh() parts.
    //! Quality can be improved a lot by oversampling a bit.
    //! Feedback is clipped independently of the input, so it doesn't disappear at high gains.

    #[macro_use]
    extern crate vst;
    use std::f32::consts::PI;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::Arc;

    use vst::buffer::AudioBuffer;
    use vst::plugin::{Category, Info, Plugin, PluginParameters};
    use vst::util::AtomicFloat;

    // this is a 4-pole filter with resonance, which is why there's 4 states and vouts
    #[derive(Clone)]
    struct LadderFilter {
        // Store a handle to the plugin's parameter object.
        params: Arc<LadderParameters>,
        // the output of the different filter stages
        vout: [f32; 4],
        // s is the "state" parameter. In an IIR it would be the last value from the filter
        // In this we find it by trapezoidal integration to avoid the unit delay
        s: [f32; 4],
    }
    struct LadderParameters {
        // the "cutoff" parameter. Determines how heavy filtering is
        cutoff: AtomicFloat,
        g: AtomicFloat,
        // needed to calculate cutoff.
        sample_rate: AtomicFloat,
        // makes a peak at cutoff
        res: AtomicFloat,
        // used to choose where we want our output to be
        poles: AtomicUsize,
        // pole_value is just to be able to use get_parameter on poles
        pole_value: AtomicFloat,
        // a drive parameter. Just used to increase the volume, which results in heavier distortion
        drive: AtomicFloat,
    }
    impl Default for LadderParameters {
        fn default() -> LadderParameters {
            LadderParameters {
                cutoff: AtomicFloat::new(1000.),
                res: AtomicFloat::new(2.),
                poles: AtomicUsize::new(3),
                pole_value : AtomicFloat::new(1.),
                drive: AtomicFloat::new(0.),
                sample_rate: AtomicFloat::new(44100.),
                g: AtomicFloat::new(0.07135868087),
            }
        }
    }
    // member methods for the struct
    impl LadderFilter {
        // the state needs to be updated after each process. Found by trapezoidal integration
        fn update_state(&mut self) {
            self.s[0] = 2. * self.vout[0] - self.s[0];
            self.s[1] = 2. * self.vout[1] - self.s[1];
            self.s[2] = 2. * self.vout[2] - self.s[2];
            self.s[3] = 2. * self.vout[3] - self.s[3];
        }
        // performs a complete filter process (mystran's method)
        fn tick_pivotal(&mut self, input: f32) {
            if self.params.drive.get() > 0. {
                self.run_ladder_nonlinear(input * (self.params.drive.get() + 0.7));
            } else {
                //
                self.run_ladder_linear(input);
            }
            self.update_state();
        }
        // nonlinear ladder filter function with distortion.
        fn run_ladder_nonlinear(&mut self, input: f32) {
            let mut a = [1f32; 5];
            let base = [input, self.s[0], self.s[1], self.s[2], self.s[3]];
            // a[n] is the fixed-pivot approximation for tanh()
            for n in 0..base.len() {
                if base[n] != 0. {
                    a[n] = base[n].tanh() / base[n];
                } else {
                    a[n] = 1.;
                }
            }
            // denominators of solutions of individual stages. Simplifies the math a bit
            let g0 = 1. / (1. + self.params.g.get() * a[1]);
            let g1 = 1. / (1. + self.params.g.get() * a[2]);
            let g2 = 1. / (1. + self.params.g.get() * a[3]);
            let g3 = 1. / (1. + self.params.g.get() * a[4]);
            //  these are just factored out of the feedback solution. Makes the math way easier to read
            let f3 = self.params.g.get() * a[3] * g3;
            let f2 = self.params.g.get() * a[2] * g2 * f3;
            let f1 = self.params.g.get() * a[1] * g1 * f2;
            let f0 = self.params.g.get() * g0 * f1;
            // outputs a 24db filter
            self.vout[3] = (f0 * input * a[0]
                + f1 * g0 * self.s[0]
                + f2 * g1 * self.s[1]
                + f3 * g2 * self.s[2]
                + g3 * self.s[3])
                / (f0 * self.params.res.get() * a[3] + 1.);
            // since we know the feedback, we can solve the remaining outputs:
            self.vout[0] = g0
                * (self.params.g.get()
                    * a[1]
                    * (input * a[0] - self.params.res.get() * a[3] * self.vout[3])
                    + self.s[0]);
            self.vout[1] = g1 * (self.params.g.get() * a[2] * self.vout[0] + self.s[1]);
            self.vout[2] = g2 * (self.params.g.get() * a[3] * self.vout[1] + self.s[2]);
        }
        // linear version without distortion
        pub fn run_ladder_linear(&mut self, input: f32) {
            // denominators of solutions of individual stages. Simplifies the math a bit
            let g0 = 1. / (1. + self.params.g.get());
            let g1 = self.params.g.get() * g0 * g0;
            let g2 = self.params.g.get() * g1 * g0;
            let g3 = self.params.g.get() * g2 * g0;
            // outputs a 24db filter
            self.vout[3] = (g3 * self.params.g.get() * input
                + g0 * self.s[3]
                + g1 * self.s[2]
                + g2 * self.s[1]
                + g3 * self.s[0])
                / (g3 * self.params.g.get() * self.params.res.get() + 1.);
            // since we know the feedback, we can solve the remaining outputs:
            self.vout[0] =
                g0 * (self.params.g.get() * (input - self.params.res.get() * self.vout[3]) + self.s[0]);
            self.vout[1] = g0 * (self.params.g.get() * self.vout[0] + self.s[1]);
            self.vout[2] = g0 * (self.params.g.get() * self.vout[1] + self.s[2]);
        }
    }
    impl LadderParameters {
        pub fn set_cutoff(&self, value: f32) {
            // cutoff formula gives us a natural feeling cutoff knob that spends more time in the low frequencies
            self.cutoff.set(20000. * (1.8f32.powf(10. * value - 10.)));
            // bilinear transformation for g gives us a very accurate cutoff
            self.g
                .set((PI * self.cutoff.get() / (self.sample_rate.get())).tan());
        }
        // returns the value used to set cutoff. for get_parameter function
        pub fn get_cutoff(&self) -> f32 {
            1. + 0.1701297528 * (0.00005 * self.cutoff.get()).ln()
        }
        pub fn set_poles(&self, value: f32) {
            self.pole_value.set(value);
            self.poles
                .store(((value * 3.).round()) as usize, Ordering::Relaxed);
        }
    }
    impl PluginParameters for LadderParameters {
        // get_parameter has to return the value used in set_parameter
        fn get_parameter(&self, index: i32) -> f32 {
            match index {
                0 => self.get_cutoff(),
                1 => self.res.get() / 4.,
                2 => self.pole_value.get(),
                3 => self.drive.get() / 5.,
                _ => 0.0,
            }
        }
        fn set_parameter(&self, index: i32, value: f32) {
            match index {
                0 => self.set_cutoff(value),
                1 => self.res.set(value * 4.),
                2 => self.set_poles(value),
                3 => self.drive.set(value * 5.),
                _ => (),
            }
        }

        fn get_parameter_name(&self, index: i32) -> String {
            match index {
                0 => "cutoff".to_string(),
                1 => "resonance".to_string(),
                2 => "filter order".to_string(),
                3 => "drive".to_string(),
                _ => "".to_string(),
            }
        }
        fn get_parameter_label(&self, index: i32) -> String {
            match index {
                0 => "Hz".to_string(),
                1 => "%".to_string(),
                2 => "poles".to_string(),
                3 => "%".to_string(),
                _ => "".to_string(),
            }
        }
        // This is what will display underneath our control.  We can
        // format it into a string that makes the most sense.
        fn get_parameter_text(&self, index: i32) -> String {
            match index {
                0 => format!("{:.0}", self.cutoff.get()),
                1 => format!("{:.3}", self.res.get()),
                2 => format!("{}", self.poles.load(Ordering::Relaxed) + 1),
                3 => format!("{:.3}", self.drive.get()),
                _ => format!(""),
            }
        }
    }
    impl Default for LadderFilter {
        fn default() -> LadderFilter {
            LadderFilter {
                vout: [0f32; 4],
                s: [0f32; 4],
                params: Arc::new(LadderParameters::default()),
            }
        }
    }
    impl Plugin for LadderFilter {
        fn set_sample_rate(&mut self, rate: f32) {
            self.params.sample_rate.set(rate);
        }
        fn get_info(&self) -> Info {
            Info {
                name: "LadderFilter".to_string(),
                unique_id: 9263,
                inputs: 1,
                outputs: 1,
                category: Category::Effect,
                parameters: 4,
                ..Default::default()
            }
        }
        fn process(&mut self, buffer: &mut AudioBuffer<f32>) {
            for (input_buffer, output_buffer) in buffer.zip() {
                for (input_sample, output_sample) in input_buffer.iter().zip(output_buffer) {
                    self.tick_pivotal(*input_sample);
                    // the poles parameter chooses which filter stage we take our output from.
                    *output_sample = self.vout[self.params.poles.load(Ordering::Relaxed)];
                }
            }
        }
        fn get_parameter_object(&mut self) -> Arc<dyn PluginParameters> {
            Arc::clone(&self.params) as Arc<dyn PluginParameters>
        }
    }
    plugin_main!(LadderFilter);
<|endoftext|>


<commit_before>//! Ignoring globs in `.gitignore` files.
//!
//! This uses a cache because the file with the globs in might not be the same
//! directory that we’re listing!

use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::RwLock;

use fs::filter::IgnorePatterns;

/// An **ignore cache** holds sets of glob patterns paired with the
/// directories that they should be ignored underneath. Believe it or not,
/// that’s a valid English sentence.
#[derive(Default, Debug)]
pub struct IgnoreCache {
    entries: RwLock<Vec<(PathBuf, IgnorePatterns)>>
}

impl IgnoreCache {
    pub fn new() -> IgnoreCache {
        IgnoreCache::default()
    }

    pub fn discover_underneath(&self, path: &Path) {
        let mut path = Some(path);
        let mut entries = self.entries.write().unwrap();

        while let Some(p) = path {
            if p.components().next().is_none() { break }

            let ignore_file = p.join(".gitignore");
            if ignore_file.is_file() {
                debug!("Found a .gitignore file: {:?}", ignore_file);
                if let Ok(mut file) = File::open(ignore_file) {
                    let mut contents = String::new();

                    match file.read_to_string(&mut contents) {
                        Ok(_) => {
                            let patterns = file_lines_to_patterns(contents.lines());
                            entries.push((p.into(), patterns));
                        }
                        Err(e) => debug!("Failed to read a .gitignore: {:?}", e)
                    }
                }
            }
            else {
                debug!("Found no .gitignore file at {:?}", ignore_file);
            }

            path = p.parent();
        }
    }

    pub fn is_ignored(&self, suspect: &Path) -> bool {
        let entries = self.entries.read().unwrap();
        entries.iter().any(|&(ref base_path, ref patterns)| {
            if let Ok(suffix) = suspect.strip_prefix(&base_path) {
                patterns.is_ignored_path(suffix)
            }
            else {
                false
            }
        })
    }
}

fn file_lines_to_patterns<'a, I>(iter: I) -> IgnorePatterns
where I: Iterator<Item=&'a str>
{
    let iter = iter.filter(|el| !el.is_empty());
    let iter = iter.filter(|el| !el.starts_with("#"));

    // Errors are currently being ignored... not a good look
    IgnorePatterns::parse_from_iter(iter).0
}

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

    #[test]
    fn parse_nothing() {
        use std::iter::empty;
        let (patterns, _) = IgnorePatterns::parse_from_iter(empty());
        assert_eq!(patterns, file_lines_to_patterns(empty()));
    }

    #[test]
    fn parse_some_globs() {
        let stuff = vec![ "*.mp3", "README.md" ];
        let reals = vec![ "*.mp3", "README.md" ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn parse_some_comments() {
        let stuff = vec![ "*.mp3", "# I am a comment!", "#", "README.md" ];
        let reals = vec![ "*.mp3",                           "README.md" ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn parse_some_blank_lines() {
        let stuff = vec![ "*.mp3", "", "", "README.md" ];
        let reals = vec![ "*.mp3",         "README.md" ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn an_empty_cache_ignores_nothing() {
        let ignores = IgnoreCache::default();
        assert_eq!(false, ignores.is_ignored(Path::new("/usr/bin/drinking")));
        assert_eq!(false, ignores.is_ignored(Path::new("target/debug/exa")));
    }
}
<commit_msg>A note to my future self<commit_after>//! Ignoring globs in `.gitignore` files.
//!
//! This uses a cache because the file with the globs in might not be the same
//! directory that we’re listing!

use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::RwLock;

use fs::filter::IgnorePatterns;

/// An **ignore cache** holds sets of glob patterns paired with the
/// directories that they should be ignored underneath. Believe it or not,
/// that’s a valid English sentence.
#[derive(Default, Debug)]
pub struct IgnoreCache {
    entries: RwLock<Vec<(PathBuf, IgnorePatterns)>>
}

impl IgnoreCache {
    pub fn new() -> IgnoreCache {
        IgnoreCache::default()
    }

    pub fn discover_underneath(&self, path: &Path) {
        let mut path = Some(path);
        let mut entries = self.entries.write().unwrap();

        while let Some(p) = path {
            if p.components().next().is_none() { break }

            let ignore_file = p.join(".gitignore");
            if ignore_file.is_file() {
                debug!("Found a .gitignore file: {:?}", ignore_file);
                if let Ok(mut file) = File::open(ignore_file) {
                    let mut contents = String::new();

                    match file.read_to_string(&mut contents) {
                        Ok(_) => {
                            let patterns = file_lines_to_patterns(contents.lines());
                            entries.push((p.into(), patterns));
                        }
                        Err(e) => debug!("Failed to read a .gitignore: {:?}", e)
                    }
                }
            }
            else {
                debug!("Found no .gitignore file at {:?}", ignore_file);
            }

            path = p.parent();
        }
    }

    pub fn is_ignored(&self, suspect: &Path) -> bool {
        let entries = self.entries.read().unwrap();
        entries.iter().any(|&(ref base_path, ref patterns)| {
            if let Ok(suffix) = suspect.strip_prefix(&base_path) {
                patterns.is_ignored_path(suffix)
            }
            else {
                false
            }
        })
    }
}

fn file_lines_to_patterns<'a, I>(iter: I) -> IgnorePatterns
where I: Iterator<Item=&'a str>
{
    let iter = iter.filter(|el| !el.is_empty());
    let iter = iter.filter(|el| !el.starts_with("#"));

    // TODO: Figure out if this should trim whitespace or not

    // Errors are currently being ignored... not a good look
    IgnorePatterns::parse_from_iter(iter).0
}

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

    #[test]
    fn parse_nothing() {
        use std::iter::empty;
        let (patterns, _) = IgnorePatterns::parse_from_iter(empty());
        assert_eq!(patterns, file_lines_to_patterns(empty()));
    }

    #[test]
    fn parse_some_globs() {
        let stuff = vec![ "*.mp3", "README.md" ];
        let reals = vec![ "*.mp3", "README.md" ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn parse_some_comments() {
        let stuff = vec![ "*.mp3", "# I am a comment!", "#", "README.md" ];
        let reals = vec![ "*.mp3",                           "README.md" ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn parse_some_blank_lines() {
        let stuff = vec![ "*.mp3", "", "", "README.md" ];
        let reals = vec![ "*.mp3",         "README.md" ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn parse_some_whitespacey_lines() {
        let stuff = vec![ " *.mp3", "  ", "  a  ", "README.md   " ];
        let reals = vec![ " *.mp3", "  ", "  a  ", "README.md   " ];
        let (patterns, _) = IgnorePatterns::parse_from_iter(reals.into_iter());
        assert_eq!(patterns, file_lines_to_patterns(stuff.into_iter()));
    }

    #[test]
    fn an_empty_cache_ignores_nothing() {
        let ignores = IgnoreCache::default();
        assert_eq!(false, ignores.is_ignored(Path::new("/usr/bin/drinking")));
        assert_eq!(false, ignores.is_ignored(Path::new("target/debug/exa")));
    }
}
<|endoftext|>


<commit_before>use std::mem;

use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;
use rand::SeedableRng;

use rayon::prelude::*;
use smallvec::SmallVec;

use tile::Faction;

use util::{Error, Direction};

use level::{GridLevel, add_isize_to_usize};

pub struct FactionGen {
    rand: XorShiftRng,
}

impl FactionGen {
    pub fn new() -> FactionGen {
        FactionGen {
            rand: XorShiftRng::rand(&mut OsRng::new().unwrap()),
        }
    }
    #[inline]
    pub fn generate(&mut self, level: &mut GridLevel<Faction>, buffer: &mut GridLevel<Faction>) {
        let mut lovel = SuperUnsafe(buffer as *mut GridLevel<Faction>);
        let width = level.get_width();
        let height = level.get_height();
        let number = self.rand.next_u32();
        {
            let level_ref = &*level;
            (0..width).into_par_iter()
                .map(|x| (x, (0..height).into_par_iter()))
                .flat_map(|(x, ys)| {
                    ys.flat_map(move |y| {
                        let x_seed = (x as u64 ^ (x as u64 >> 32)) as u32;
                        let y_seed = (y as u64 ^ (y as u64 >> 32)) as u32;
                        let mut rand = XorShiftRng::from_seed([number, x_seed, y_seed, 1]);
                        rand.next_u32();
                        rand.next_u32();
                        let mut deck = SmallVec::<[_; 9]>::new();
                        match level_ref.get_tile(x, y) {
                            Ok(tile) => {
                                match *tile {
                                    Faction::Faction(_) => {
                                        deck.push(tile.clone());
                                    },
                                    Faction::Void => return None,
                                    _ => {},
                                }
                            },
                            Err(Error::IndexOutOfBounds) => {
                                unreachable!("Generate method indexed out of bounds while simulating a step. This should never happen unless the programmer is not very bright.");
                            }
                        }
                        Self::get_faction_neighbours(x, y, &mut deck, level_ref);
                        rand.choose(&deck)
                            .map(|f| ((x, y), f.clone()))
                    })
                })
                .for_each(|((x, y), f)| {
                    //this should be safe, right?
                    if let Ok(tile) = unsafe{ &mut *lovel.0 }.get_mut_tile(x, y) {
                        *tile = f;
                    }
                });
        }
        mem::swap(level, buffer);
    }

    fn get_faction_neighbours(x: usize, y: usize, deck: &mut SmallVec<[Faction;9]>, level: &GridLevel<Faction>) {
        for d in Direction::get_dirs() {
            let (ix, iy) = d.get_tuple();
            let coord = match (add_isize_to_usize(ix, x), add_isize_to_usize(iy, y)) {
                (Some(x), Some(y)) => (x,y),
                _ => continue,
            };
            match level.get_tile_with_tuple(coord) {
                Ok(f @ &Faction::Faction(_)) => deck.push(f.clone()),
                _ => {},
            }
        }
    }
}
//this struct is unsafe. Use it with great caution.
struct SuperUnsafe(*mut GridLevel<Faction>);
unsafe impl Sync for SuperUnsafe{}
<commit_msg>lovel made not mutable<commit_after>use std::mem;

use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;
use rand::SeedableRng;

use rayon::prelude::*;
use smallvec::SmallVec;

use tile::Faction;

use util::{Error, Direction};

use level::{GridLevel, add_isize_to_usize};

pub struct FactionGen {
    rand: XorShiftRng,
}

impl FactionGen {
    pub fn new() -> FactionGen {
        FactionGen {
            rand: XorShiftRng::rand(&mut OsRng::new().unwrap()),
        }
    }
    #[inline]
    pub fn generate(&mut self, level: &mut GridLevel<Faction>, buffer: &mut GridLevel<Faction>) {
        let lovel = SuperUnsafe(buffer as *mut GridLevel<Faction>);
        let width = level.get_width();
        let height = level.get_height();
        let number = self.rand.next_u32();
        {
            let level_ref = &*level;
            (0..width).into_par_iter()
                .map(|x| (x, (0..height).into_par_iter()))
                .flat_map(|(x, ys)| {
                    ys.flat_map(move |y| {
                        let x_seed = (x as u64 ^ (x as u64 >> 32)) as u32;
                        let y_seed = (y as u64 ^ (y as u64 >> 32)) as u32;
                        let mut rand = XorShiftRng::from_seed([number, x_seed, y_seed, 1]);
                        rand.next_u32();
                        rand.next_u32();
                        let mut deck = SmallVec::<[_; 9]>::new();
                        match level_ref.get_tile(x, y) {
                            Ok(tile) => {
                                match *tile {
                                    Faction::Faction(_) => {
                                        deck.push(tile.clone());
                                    },
                                    Faction::Void => return None,
                                    _ => {},
                                }
                            },
                            Err(Error::IndexOutOfBounds) => {
                                unreachable!("Generate method indexed out of bounds while simulating a step. This should never happen unless the programmer is not very bright.");
                            }
                        }
                        Self::get_faction_neighbours(x, y, &mut deck, level_ref);
                        rand.choose(&deck)
                            .map(|f| ((x, y), f.clone()))
                    })
                })
                .for_each(|((x, y), f)| {
                    //this should be safe, right?
                    if let Ok(tile) = unsafe{ &mut *lovel.0 }.get_mut_tile(x, y) {
                        *tile = f;
                    }
                });
        }
        mem::swap(level, buffer);
    }

    fn get_faction_neighbours(x: usize, y: usize, deck: &mut SmallVec<[Faction;9]>, level: &GridLevel<Faction>) {
        for d in Direction::get_dirs() {
            let (ix, iy) = d.get_tuple();
            let coord = match (add_isize_to_usize(ix, x), add_isize_to_usize(iy, y)) {
                (Some(x), Some(y)) => (x,y),
                _ => continue,
            };
            match level.get_tile_with_tuple(coord) {
                Ok(f @ &Faction::Faction(_)) => deck.push(f.clone()),
                _ => {},
            }
        }
    }
}
//this struct is unsafe. Use it with great caution.
struct SuperUnsafe(*mut GridLevel<Faction>);
unsafe impl Sync for SuperUnsafe{}
<|endoftext|>


<commit_before>extern crate rand;
extern crate time;
#[macro_use]
extern crate clap;
extern crate presort;

use std::fs::OpenOptions;
use std::io::Write;
use rand::Rng;
use time::Duration;
use clap::{App, Arg};
use presort::{PresortedVec, PermutedVec, SortVec};
use presort::inc_tree::{Tree, IncTree, dump, update};

fn main() {
    //command-line
    let args = App::new("presort_bench")
    .arg(Arg::with_name("vec")
        .long("vec")
        .help("Use the default vector implementation")
        .conflicts_with_all(&["presort","presort_pad","permut","permut_pad"])
    ).arg(Arg::with_name("presort")
        .long("presort")
        .help("Use the presorted vector implementation")
        .conflicts_with_all(&["vec","presort_pad","permut","permut_pad"])
    ).arg(Arg::with_name("presort_pad")
        .long("presort_pad")
        .help("Use the persorted vector implementation with padding")
        .conflicts_with_all(&["vec","presort","permut","permut_pad"])
    ).arg(Arg::with_name("permut")
        .long("permut")
        .help("Use the permuted vector implementation")
        .conflicts_with_all(&["vec","presort","persort_pad","permut_pad"])
    ).arg(Arg::with_name("permut_pad")
        .long("permut_pad")
        .help("Use the permuted vector implementation with padding")
        .conflicts_with_all(&["vec","presort","persort_pad","permut"])
    ).args_from_usage("\
        --tag [tag]                                 'max depth of initial tree'
        [initial_max_depth] -d [initial_max_depth]  'max depth of initial tree'
        [initial_nodes] -n [initial_nodes]          'nodes of initial tree'
        [removals] -r [removals]                    'branches to remove (currently unused)'
        [additions] -a [additions]                  'branches to add'
        [edits] -e [edits]                          'nodes to modify'
        [change] -c [change]                        'chance to change sort order'
        [trials] -t [trials]                        'repetitions'
        [outfile] -o [outfile]                      'append output to this file'
        [header] -h                                 'write out a header to the results' ")
    .get_matches();
    let tag = match args.value_of("tag") {
        None => "none",
        Some(t) => t
    };
    let d = value_t!(args.value_of("initial_max_depth"), usize).unwrap_or(13);
    let n = value_t!(args.value_of("initial_nodes"), usize).unwrap_or(10000);
    let r = value_t!(args.value_of("removals"), usize).unwrap_or(0);
    let a = value_t!(args.value_of("additions"), usize).unwrap_or(0);
    let e = value_t!(args.value_of("edits"), usize).unwrap_or(0);
    let c = value_t!(args.value_of("change"), f32).unwrap_or(0.5);
    let t = value_t!(args.value_of("trials"), usize).unwrap_or(1);
    let mut o: Box<Write> = if let Some(f) = args.value_of("outfile") {
        Box::new(
            OpenOptions::new()
            .create(true)
            .write(true)
            .append(true)
            .open(f)
            .unwrap()
        )
    } else { Box::new(std::io::stdout()) };

    //write out header
    if args.is_present("header"){
        writeln!(o, "{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
            "timestamp",
            "user_tag",
            "vec_type",
            "depth",
            "nodes",
            "removals",
            "additions",
            "edits",
            "change_chance",
            "time_dump",
            "time_init_sort",
            "time_modification",
            "time_update",
            "time_sort"
        ).unwrap();
    }

    for _ in 0..t {
        //create target vector
        let mut vec =
            if args.is_present("vec") {
                VecVersion::Vec(Vec::new())
            } else if args.is_present("presort") {
                VecVersion::Presort(PresortedVec::new())
            } else if args.is_present("presort_pad") {
                unimplemented!()
            } else if args.is_present("permuted") {
                VecVersion::Permut(PermutedVec::new())
            } else if args.is_present("permuted_pad") {
                unimplemented!()
            } else {
                VecVersion::Vec(Vec::new())
            };

        //initial tree creation
        let mut tree = build_tree(d,n);

        //initial dump
        let dur_dump = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => dump(&tree, v),
                VecVersion::Presort(ref mut v) => dump(&tree, v),
                VecVersion::PrePad(ref mut v) => dump(&tree, v),
                VecVersion::Permut(ref mut v) => dump(&tree, v),
                VecVersion::PerPad(ref mut v) => dump(&tree, v),
            };
        });

        //initial sort
        let dur_init_sort = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => v.sort(),
                VecVersion::Presort(ref mut v) => v.sort(),
                VecVersion::PrePad(ref mut v) => v.sort(),
                VecVersion::Permut(ref mut v) => v.sort(),
                VecVersion::PerPad(ref mut v) => v.sort(),
            };
        });

        //modify tree
        let dur_modify = Duration::span(||{
            let mut rng = rand::thread_rng();
            remove_branches(&tree, d, r);
            add_branches(&tree, d, a);
            if rng.gen::<f32>() < c {
                mutate_vals(&tree, d, e);
            } else {
                incr_vals(&tree, d, e);
            }
        });

        //update tree
        let dur_update = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => update(&tree, 0, v),
                VecVersion::Presort(ref mut v) => update(&tree, 0, v),
                VecVersion::PrePad(ref mut v) => update(&tree, 0, v),
                VecVersion::Permut(ref mut v) => update(&tree, 0, v),
                VecVersion::PerPad(ref mut v) => update(&tree, 0, v),
            };
        });

        //sort tree
        let dur_sort = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => v.sort(),
                VecVersion::Presort(ref mut v) => v.sort(),
                VecVersion::PrePad(ref mut v) => v.sort(),
                VecVersion::Permut(ref mut v) => v.sort(),
                VecVersion::PerPad(ref mut v) => v.sort(),
            };
        });

        //write out results
        writeln!(o, "{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
            time::precise_time_s() as usize,
            tag,vec.ver(),d,n,r,a,e,c,
            dur_dump.num_nanoseconds().unwrap(),
            dur_init_sort.num_nanoseconds().unwrap(),
            dur_modify.num_nanoseconds().unwrap(),
            dur_update.num_nanoseconds().unwrap(),
            dur_sort.num_nanoseconds().unwrap()
        ).unwrap();
    }
}

enum VecVersion<T: Ord> {
    Vec(Vec<T>),
    Presort(PresortedVec<T>),
    PrePad(PresortedVec<T>),
    Permut(PermutedVec<T>),
    PerPad(PermutedVec<T>),
}

impl<T: Ord> VecVersion<T> {
    fn ver(&self) -> &str {
        match *self {
            VecVersion::Vec(_) => "vec",
            VecVersion::Presort(_) => "presorted",
            VecVersion::PrePad(_) => "presorted_pad",
            VecVersion::Permut(_) => "permuted",
            VecVersion::PerPad(_) => "permuted_pad",
        }
    }
}

//creates a random tree with the requested parameters
fn build_tree(max_depth: usize, nodes: usize) -> Tree<usize> {
    let mut rng = rand::thread_rng();

    let tree = Tree::new_node(rng.gen());

    for _ in 0..nodes {
        let mut branch = tree.clone();
        let depth = rng.gen::<usize>() % max_depth;
        for _ in 0..depth {
            let num = branch.num_children();
            if num <= 0 {break};
            branch = branch.get_child(rng.gen::<usize>() % num);
        }
        branch.push_child(Tree::new_node(rng.gen()));
    }

    tree
}

fn random_subtree(tree: &Tree<usize>, high_depth: usize) -> Tree<usize> {
    let mut rng = rand::thread_rng();
    let mut subtree = tree.clone();
    let depth = rng.gen::<usize>() % high_depth;
    for _ in 0..depth {
        let num = subtree.num_children();
        if num <= 0 { return subtree; }
        subtree = subtree.get_child(rng.gen::<usize>() % num);
    }
    return subtree;
}

fn mutate_vals(tree: &Tree<usize>, high_depth: usize, edits: usize) {
    let mut rng = rand::thread_rng();
    for _ in 0..edits {
        random_subtree(tree, high_depth).set_data(rng.gen());
    }
}

fn incr_vals(tree: &Tree<usize>, high_depth: usize, edits: usize) {
    for _ in 0..edits {
        let subtree = random_subtree(tree, high_depth);
        subtree.set_data(subtree.get_data() + 1);
    }
}

fn add_branches(tree: &Tree<usize>, high_depth: usize, adds: usize) {
    let mut rng = rand::thread_rng();
    for _ in 0..adds {
        random_subtree(tree, high_depth).push_child(Tree::new_node(rng.gen()));
    }
}

fn remove_branches(tree: &Tree<usize>, high_depth: usize, removes: usize) {
    let mut i = 0;
    while i<removes {
        if let Some(_) = random_subtree(tree, high_depth).pop_child() {
            i = i + 1;
        }
    }
}

<commit_msg>implemented padding<commit_after>extern crate rand;
extern crate time;
#[macro_use]
extern crate clap;
extern crate presort;

use std::fs::OpenOptions;
use std::io::Write;
use rand::Rng;
use time::Duration;
use clap::{App, Arg};
use presort::{PresortedVec, PermutedVec, SortVec};
use presort::inc_tree::{Tree, IncTree, dump, update, update_no_pad};

fn main() {
    //command-line
    let args = App::new("presort_bench")
    .arg(Arg::with_name("vec")
        .long("vec")
        .help("Use the default vector implementation")
        .conflicts_with_all(&["presort","presort_pad","permut","permut_pad"])
    ).arg(Arg::with_name("presort")
        .long("presort")
        .help("Use the presorted vector implementation")
        .conflicts_with_all(&["vec","presort_pad","permut","permut_pad"])
    ).arg(Arg::with_name("presort_pad")
        .long("presort_pad")
        .help("Use the persorted vector implementation with padding")
        .conflicts_with_all(&["vec","presort","permut","permut_pad"])
    ).arg(Arg::with_name("permut")
        .long("permut")
        .help("Use the permuted vector implementation")
        .conflicts_with_all(&["vec","presort","persort_pad","permut_pad"])
    ).arg(Arg::with_name("permut_pad")
        .long("permut_pad")
        .help("Use the permuted vector implementation with padding")
        .conflicts_with_all(&["vec","presort","persort_pad","permut"])
    ).args_from_usage("\
        --tag [tag]                                 'max depth of initial tree'
        [initial_max_depth] -d [initial_max_depth]  'max depth of initial tree'
        [initial_nodes] -n [initial_nodes]          'nodes of initial tree'
        [removals] -r [removals]                    'branches to remove (currently unused)'
        [additions] -a [additions]                  'branches to add'
        [edits] -e [edits]                          'nodes to modify'
        [change] -c [change]                        'chance to change sort order'
        [trials] -t [trials]                        'repetitions'
        [outfile] -o [outfile]                      'append output to this file'
        [header] -h                                 'write out a header to the results' ")
    .get_matches();
    let tag = match args.value_of("tag") {
        None => "none",
        Some(t) => t
    };
    let d = value_t!(args.value_of("initial_max_depth"), usize).unwrap_or(13);
    let n = value_t!(args.value_of("initial_nodes"), usize).unwrap_or(10000);
    let r = value_t!(args.value_of("removals"), usize).unwrap_or(0);
    let a = value_t!(args.value_of("additions"), usize).unwrap_or(0);
    let e = value_t!(args.value_of("edits"), usize).unwrap_or(0);
    let c = value_t!(args.value_of("change"), f32).unwrap_or(0.5);
    let t = value_t!(args.value_of("trials"), usize).unwrap_or(1);
    let mut o: Box<Write> = if let Some(f) = args.value_of("outfile") {
        Box::new(
            OpenOptions::new()
            .create(true)
            .write(true)
            .append(true)
            .open(f)
            .unwrap()
        )
    } else { Box::new(std::io::stdout()) };

    //write out header
    if args.is_present("header"){
        writeln!(o, "{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
            "timestamp",
            "user_tag",
            "vec_type",
            "depth",
            "nodes",
            "removals",
            "additions",
            "edits",
            "change_chance",
            "time_dump",
            "time_init_sort",
            "time_modification",
            "time_update",
            "time_sort"
        ).unwrap();
    }

    for _ in 0..t {
        //create target vector
        let mut vec =
            if args.is_present("vec") {
                VecVersion::Vec(Vec::new())
            } else if args.is_present("presort") {
                VecVersion::Presort(PresortedVec::new())
            } else if args.is_present("presort_pad") {
                VecVersion::PrePad(PresortedVec::new())
            } else if args.is_present("permuted") {
                VecVersion::Permut(PermutedVec::new())
            } else if args.is_present("permuted_pad") {
                VecVersion::PerPad(PermutedVec::new())
            } else {
                VecVersion::Vec(Vec::new())
            };

        //initial tree creation
        let tree = build_tree(d,n);

        //initial dump
        let dur_dump = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => dump(&tree, v),
                VecVersion::Presort(ref mut v) => dump(&tree, v),
                VecVersion::PrePad(ref mut v) => dump(&tree, v),
                VecVersion::Permut(ref mut v) => dump(&tree, v),
                VecVersion::PerPad(ref mut v) => dump(&tree, v),
            };
        });

        //initial sort
        let dur_init_sort = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => v.sort(),
                VecVersion::Presort(ref mut v) => v.sort(),
                VecVersion::PrePad(ref mut v) => v.sort(),
                VecVersion::Permut(ref mut v) => v.sort(),
                VecVersion::PerPad(ref mut v) => v.sort(),
            };
        });

        //modify tree
        let dur_modify = Duration::span(||{
            let mut rng = rand::thread_rng();
            remove_branches(&tree, d, r);
            add_branches(&tree, d, a);
            if rng.gen::<f32>() < c {
                mutate_vals(&tree, d, e);
            } else {
                incr_vals(&tree, d, e);
            }
        });

        //update tree
        let dur_update = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => update_no_pad(&tree, 0, v),
                VecVersion::Presort(ref mut v) => update_no_pad(&tree, 0, v),
                VecVersion::PrePad(ref mut v) => update(&tree, 0, v),
                VecVersion::Permut(ref mut v) => update_no_pad(&tree, 0, v),
                VecVersion::PerPad(ref mut v) => update(&tree, 0, v),
            };
        });

        //sort tree
        let dur_sort = Duration::span(||{
            match vec {
                VecVersion::Vec(ref mut v) => v.sort(),
                VecVersion::Presort(ref mut v) => v.sort(),
                VecVersion::PrePad(ref mut v) => v.sort(),
                VecVersion::Permut(ref mut v) => v.sort(),
                VecVersion::PerPad(ref mut v) => v.sort(),
            };
        });

        //write out results
        writeln!(o, "{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
            time::precise_time_s() as usize,
            tag,vec.ver(),d,n,r,a,e,c,
            dur_dump.num_nanoseconds().unwrap(),
            dur_init_sort.num_nanoseconds().unwrap(),
            dur_modify.num_nanoseconds().unwrap(),
            dur_update.num_nanoseconds().unwrap(),
            dur_sort.num_nanoseconds().unwrap()
        ).unwrap();
    }
}

enum VecVersion<T: Ord> {
    Vec(Vec<T>),
    Presort(PresortedVec<T>),
    PrePad(PresortedVec<T>),
    Permut(PermutedVec<T>),
    PerPad(PermutedVec<T>),
}

impl<T: Ord> VecVersion<T> {
    fn ver(&self) -> &str {
        match *self {
            VecVersion::Vec(_) => "vec",
            VecVersion::Presort(_) => "presorted",
            VecVersion::PrePad(_) => "presorted_pad",
            VecVersion::Permut(_) => "permuted",
            VecVersion::PerPad(_) => "permuted_pad",
        }
    }
}

//creates a random tree with the requested parameters
fn build_tree(max_depth: usize, nodes: usize) -> Tree<usize> {
    let mut rng = rand::thread_rng();

    let tree = Tree::new_node(rng.gen());

    for _ in 0..nodes {
        let mut branch = tree.clone();
        let depth = rng.gen::<usize>() % max_depth;
        for _ in 0..depth {
            let num = branch.num_children();
            if num <= 0 {break};
            branch = branch.get_child(rng.gen::<usize>() % num);
        }
        branch.push_child(Tree::new_node(rng.gen()));
    }

    tree
}

fn random_subtree(tree: &Tree<usize>, high_depth: usize) -> Tree<usize> {
    let mut rng = rand::thread_rng();
    let mut subtree = tree.clone();
    let depth = rng.gen::<usize>() % high_depth;
    for _ in 0..depth {
        let num = subtree.num_children();
        if num <= 0 { return subtree; }
        subtree = subtree.get_child(rng.gen::<usize>() % num);
    }
    return subtree;
}

fn mutate_vals(tree: &Tree<usize>, high_depth: usize, edits: usize) {
    let mut rng = rand::thread_rng();
    for _ in 0..edits {
        random_subtree(tree, high_depth).set_data(rng.gen());
    }
}

fn incr_vals(tree: &Tree<usize>, high_depth: usize, edits: usize) {
    for _ in 0..edits {
        let subtree = random_subtree(tree, high_depth);
        subtree.set_data(subtree.get_data() + 1);
    }
}

fn add_branches(tree: &Tree<usize>, high_depth: usize, adds: usize) {
    let mut rng = rand::thread_rng();
    for _ in 0..adds {
        random_subtree(tree, high_depth).push_child(Tree::new_node(rng.gen()));
    }
}

fn remove_branches(tree: &Tree<usize>, high_depth: usize, removes: usize) {
    let mut i = 0;
    while i<removes {
        if let Some(_) = random_subtree(tree, high_depth).pop_child() {
            i = i + 1;
        }
    }
}

<|endoftext|>


<commit_before>use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::{HelperDef, HelperResult};
use crate::json::value::JsonTruthy;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext, Renderable};

#[derive(Clone, Copy)]
pub struct IfHelper {
    positive: bool,
}

impl HelperDef for IfHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        let param = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"if\""))?;
        let include_zero = h
            .hash_get("includeZero")
            .and_then(|v| v.value().as_bool())
            .unwrap_or(false);

        let mut value = param.value().is_truthy(include_zero);

        if !self.positive {
            value = !value;
        }

        let tmpl = if value { h.template() } else { h.inverse() };
        match tmpl {
            Some(ref t) => t.render(r, ctx, rc, out),
            None => Ok(()),
        }
    }
}

pub static IF_HELPER: IfHelper = IfHelper { positive: true };
pub static UNLESS_HELPER: IfHelper = IfHelper { positive: false };

#[cfg(test)]
mod test {
    use crate::helpers::WITH_HELPER;
    use crate::registry::Registry;
    use serde_json::value::Value as Json;
    use std::str::FromStr;

    #[test]
    fn test_if() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#if this}}hello{{/if}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#unless this}}hello{{else}}world{{/unless}}")
            .is_ok());

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.ok().unwrap(), "hello".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t0", &false);
        assert_eq!(r2.ok().unwrap(), "".to_string());
    }

    #[test]
    fn test_if_context() {
        let json_str = r#"{"a":{"b":99,"c":{"d": true}}}"#;
        let data = Json::from_str(json_str).unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_helper("with", Box::new(WITH_HELPER));
        assert!(handlebars
            .register_template_string("t0", "{{#if a.c.d}}hello {{a.b}}{{/if}}")
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t1",
                "{{#with a}}{{#if c.d}}hello {{../a.b}}{{/if}}{{/with}}"
            )
            .is_ok());

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.unwrap(), "hello 99".to_string());

        let r1 = handlebars.render("t1", &data);
        assert_eq!(r1.unwrap(), "hello 99".to_string());
    }

    #[test]
    fn test_if_include_zero() {
        use std::f64;
        let handlebars = Registry::new();

        assert_eq!(
            "0".to_owned(),
            handlebars
                .render_template("{{#if a}}1{{else}}0{{/if}}", &json!({"a": 0}))
                .unwrap()
        );
        assert_eq!(
            "1".to_owned(),
            handlebars
                .render_template(
                    "{{#if a includeZero=true}}1{{else}}0{{/if}}",
                    &json!({"a": 0})
                )
                .unwrap()
        );
        assert_eq!(
            "0".to_owned(),
            handlebars
                .render_template(
                    "{{#if a includeZero=true}}1{{else}}0{{/if}}",
                    &json!({ "a": f64::NAN })
                )
                .unwrap()
        );
    }

    #[test]
    fn test_invisible_line_stripping() {
        let hbs = Registry::new();
        assert_eq!(
            "yes\n",
            hbs.render_template("{{#if a}}\nyes\n{{/if}}\n", &json!({"a": true}))
                .unwrap()
        );
    }
}
<commit_msg>(test) add test case to reproduce #447<commit_after>use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::{HelperDef, HelperResult};
use crate::json::value::JsonTruthy;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext, Renderable};

#[derive(Clone, Copy)]
pub struct IfHelper {
    positive: bool,
}

impl HelperDef for IfHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        let param = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"if\""))?;
        let include_zero = h
            .hash_get("includeZero")
            .and_then(|v| v.value().as_bool())
            .unwrap_or(false);

        let mut value = param.value().is_truthy(include_zero);

        if !self.positive {
            value = !value;
        }

        let tmpl = if value { h.template() } else { h.inverse() };
        match tmpl {
            Some(ref t) => t.render(r, ctx, rc, out),
            None => Ok(()),
        }
    }
}

pub static IF_HELPER: IfHelper = IfHelper { positive: true };
pub static UNLESS_HELPER: IfHelper = IfHelper { positive: false };

#[cfg(test)]
mod test {
    use crate::helpers::WITH_HELPER;
    use crate::registry::Registry;
    use serde_json::value::Value as Json;
    use std::str::FromStr;

    #[test]
    fn test_if() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#if this}}hello{{/if}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#unless this}}hello{{else}}world{{/unless}}")
            .is_ok());

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.ok().unwrap(), "hello".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t0", &false);
        assert_eq!(r2.ok().unwrap(), "".to_string());
    }

    #[test]
    fn test_if_context() {
        let json_str = r#"{"a":{"b":99,"c":{"d": true}}}"#;
        let data = Json::from_str(json_str).unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_helper("with", Box::new(WITH_HELPER));
        assert!(handlebars
            .register_template_string("t0", "{{#if a.c.d}}hello {{a.b}}{{/if}}")
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t1",
                "{{#with a}}{{#if c.d}}hello {{../a.b}}{{/if}}{{/with}}"
            )
            .is_ok());

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.unwrap(), "hello 99".to_string());

        let r1 = handlebars.render("t1", &data);
        assert_eq!(r1.unwrap(), "hello 99".to_string());
    }

    #[test]
    fn test_if_include_zero() {
        use std::f64;
        let handlebars = Registry::new();

        assert_eq!(
            "0".to_owned(),
            handlebars
                .render_template("{{#if a}}1{{else}}0{{/if}}", &json!({"a": 0}))
                .unwrap()
        );
        assert_eq!(
            "1".to_owned(),
            handlebars
                .render_template(
                    "{{#if a includeZero=true}}1{{else}}0{{/if}}",
                    &json!({"a": 0})
                )
                .unwrap()
        );
        assert_eq!(
            "0".to_owned(),
            handlebars
                .render_template(
                    "{{#if a includeZero=true}}1{{else}}0{{/if}}",
                    &json!({ "a": f64::NAN })
                )
                .unwrap()
        );
    }

    #[test]
    fn test_invisible_line_stripping() {
        let hbs = Registry::new();
        assert_eq!(
            "yes\n",
            hbs.render_template("{{#if a}}\nyes\n{{/if}}\n", &json!({"a": true}))
                .unwrap()
        );

        assert_eq!(
            "x\ny",
            hbs.render_template("{{#if a}}x{{/if}}\ny", &json!({"a": true}))
                .unwrap()
        );
    }
}
<|endoftext|>