<commit_before>/**
 * > Every morning in the early part of October 1843, on my coming down to
 *   breakfast, your brother William Edward and yourself used to ask me: "Well,
 *   Papa, can you multiply triples?" Whereto I was always obliged to reply,
 *   with a sad shake of the head, "No, I can only add and subtract them."
 *
 *   Sir William Hamilton
 */

use core::cast::transmute;
use core::cmp::{Eq, Ord};
use core::ptr::to_unsafe_ptr;
use core::sys::size_of;
use core::vec::raw::buf_as_slice;

use std::cmp::FuzzyEq;

use dim::{Dimensional, ToPtr};
use funs::common::*;
use funs::exponential::*;
use funs::triganomic::*;
use mat::{Mat3, Mat4};
use num::kinds::{Float, Number};
use vec::Vec3;

/**
 * The base quaternion trait
 *
 * # Type parameters
 *
 * * `T` - The type of the components. Should be a floating point type.
 * * `V3` - The 3-dimensional vector type that will containin the imaginary
 *          components of the quaternion.
 */
pub trait Quaternion<T,V3>: Dimensional<T>, ToPtr<T>, Eq, Neg<self> {
    /**
     * # Return value
     *
     * The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
     */
    static pure fn identity() -> self;

    /**
     * # Return value
     *
     * The additive identity, ie: `q = 0 + 0i + 0j + 0i`
     */
    static pure fn zero() -> self;

    /**
     * # Return value
     *
     * The result of multiplying the quaternion a scalar
     */
    pure fn mul_t(&self, value: T) -> self;

    /**
     * # Return value
     *
     * The result of dividing the quaternion a scalar
     */
    pure fn div_t(&self, value: T) -> self;

    /**
     * # Return value
     *
     * The result of multiplying the quaternion by a vector
     */
    pure fn mul_v(&self, vec: &V3) -> V3;

    /**
     * # Return value
     *
     * The sum of this quaternion and `other`
     */
    pure fn add_q(&self, other: &self) -> self;

    /**
     * # Return value
     *
     * The sum of this quaternion and `other`
     */
    pure fn sub_q(&self, other: &self) -> self;

    /**
     * # Return value
     *
     * The the result of multipliplying the quaternion by `other`
     */
    pure fn mul_q(&self, other: &self) -> self;

    /**
     * # Return value
     *
     * The dot product of the quaternion and `other`
     */
    pure fn dot(&self, other: &self) -> T;

    /**
     * # Return value
     *
     * The conjugate of the quaternion
     */
    pure fn conjugate(&self) -> self;

    /**
     * # Return value
     *
     * The multiplicative inverse of the quaternion
     */
    pure fn inverse(&self) -> self;

    /**
     * # Return value
     *
     * The squared magnitude of the quaternion. This is useful for
     * magnitude comparisons where the exact magnitude does not need to be
     * calculated.
     */
    pure fn magnitude2(&self) -> T;

    /**
     * # Return value
     *
     * The magnitude of the quaternion
     *
     * # Performance notes
     *
     * For instances where the exact magnitude of the quaternion does not need
     * to be known, for example for quaternion-quaternion magnitude comparisons,
     * it is advisable to use the `magnitude2` method instead.
     */
    pure fn magnitude(&self) -> T;

    /**
     * # Return value
     *
     * The normalized quaternion
     */
    pure fn normalize(&self) -> self;

    /**
     * Normalised linear interpolation
     *
     * # Return value
     *
     * The intoperlated quaternion
     */
    pure fn nlerp(&self, other: &self, amount: T) -> self;

    /**
     * Perform a spherical linear interpolation between the quaternion and
     * `other`.
     *
     * # Return value
     *
     * The intoperlated quaternion
     *
     * # Performance notes
     *
     * This is more accurate than `nlerp` but is also more
     * computationally intensive.
     */
    pure fn slerp(&self, other: &self, amount: T) -> self;

    /**
     * Convert the quaternion to a 3 x 3 rotation matrix
     */
    pure fn to_mat3(&self) -> Mat3<T>;

    /**
     * Convert the quaternion to a 4 x 4 transformation matrix
     */
    pure fn to_mat4(&self) -> Mat4<T>;
}

pub trait ToQuat<T> {
    /**
     * Convert `self` to a quaternion
     */
    pure fn to_Quat() -> Quat<T>;
}

/**
 * A quaternion in scalar/vector form
 *
 * # Type parameters
 *
 * * `T` - The type of the components. Should be a floating point type.
 *
 * # Fields
 *
 * * `s` - the scalar component
 * * `v` - a vector containing the three imaginary components
 */
pub struct Quat<T> { s: T, v: Vec3<T> }

pub impl<T> Quat<T> {
    /**
     * Construct the quaternion from one scalar component and three
     * imaginary components
     *
     * # Arguments
     *
     * * `w`  - the scalar component
     * * `xi` - the fist imaginary component
     * * `yj` - the second imaginary component
     * * `zk` - the third imaginary component
     */
    #[inline(always)]
    static pure fn new(w: T, xi: T, yj: T, zk: T) -> Quat<T> {
        Quat::from_sv(move w, move Vec3::new(move xi, move yj, move zk))
    }

    /**
     * Construct the quaternion from a scalar and a vector
     *
     * # Arguments
     *
     * * `s` - the scalar component
     * * `v` - a vector containing the three imaginary components
     */
    #[inline(always)]
    static pure fn from_sv(s: T, v: Vec3<T>) -> Quat<T> {
        Quat { s: move s, v: move v }
    }
}

pub impl<T> Quat<T>: Dimensional<T> {
    #[inline(always)]
    static pure fn dim() -> uint { 4 }

    #[inline(always)]
    static pure fn size_of() -> uint { size_of::<Quat<T>>() }
}

pub impl<T:Copy> Quat<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(i: uint) -> T {
        unsafe { do buf_as_slice(self.to_ptr(), 4) |slice| { slice[i] } }
    }
}

pub impl<T:Copy> Quat<T>: ToPtr<T> {
    #[inline(always)]
    pure fn to_ptr(&self) -> *T {
        unsafe {
            transmute::<*Quat<T>, *T>(
                to_unsafe_ptr(&*self)
            )
        }
    }
}

pub impl<T:Copy Float Exp Extent InvTrig> Quat<T>: Quaternion<T, Vec3<T>> {
    #[inline(always)]
    static pure fn identity() -> Quat<T> {
        Quat::new(Number::from(1),
                  Number::from(0),
                  Number::from(0),
                  Number::from(0))
    }

    #[inline(always)]
    static pure fn zero() -> Quat<T> {
        Quat::new(Number::from(0),
                  Number::from(0),
                  Number::from(0),
                  Number::from(0))
    }

    #[inline(always)]
    pure fn mul_t(&self, value: T) -> Quat<T> {
        Quat::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(&self, value: T) -> Quat<T> {
        Quat::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn mul_v(&self, vec: &Vec3<T>) -> Vec3<T>  {
        let tmp = self.v.cross(vec).add_v(&vec.mul_t(self.s));
        self.v.cross(&tmp).mul_t(Number::from(2)).add_v(vec)
    }

    #[inline(always)]
    pure fn add_q(&self, other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_q(&self, other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_q(&self, other: &Quat<T>) -> Quat<T> {
        Quat::new(self.s * other.s   - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z,
                  self.s * other.v.x + self.v.x * other.s   + self.v.y * other.v.z - self.v.z * other.v.y,
                  self.s * other.v.y + self.v.y * other.s   + self.v.z * other.v.x - self.v.x * other.v.z,
                  self.s * other.v.z + self.v.z * other.s   + self.v.x * other.v.y - self.v.y * other.v.x)
    }

    #[inline(always)]
    pure fn dot(&self, other: &Quat<T>) -> T {
        self.s * other.s + self.v.dot(&other.v)
    }

    #[inline(always)]
    pure fn conjugate(&self) -> Quat<T> {
        Quat::from_sv(self.s, -self.v)
    }

    #[inline(always)]
    pure fn inverse(&self) -> Quat<T> {
        self.conjugate().div_t(self.magnitude2())
    }

    #[inline(always)]
    pure fn magnitude2(&self) -> T {
        self.s * self.s + self.v.length2()
    }

    #[inline(always)]
    pure fn magnitude(&self) -> T {
        self.magnitude2().sqrt()
    }

    #[inline(always)]
    pure fn normalize(&self) -> Quat<T> {
        let mut n: T = Number::from(1);
        n /= self.magnitude();
        return self.mul_t(n);
    }

    #[inline(always)]
    pure fn nlerp(&self, other: &Quat<T>, amount: T) -> Quat<T> {
        let _1: T = Number::from(1);
        self.mul_t(_1 - amount).add_q(&other.mul_t(amount)).normalize()
    }

    /**
     * Spherical Linear Intoperlation
     *
     * Both quaternions should be normalized first, or else strange things will
     * will happen...
     *
     * # Performance notes
     *
     * The `acos` operation used in `slerp` is an expensive operation, so unless
     * your quarternions a far away from each other it's generally more advisable
     * to use `nlerp` when you know your rotations are going to be small.
     *
     * - [Understanding Slerp, Then Not Using It]
     *   (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)
     * - [Arcsynthesis OpenGL tutorial]
     *   (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
     */
    #[inline(always)]
    pure fn slerp(&self, other: &Quat<T>, amount: T) -> Quat<T> {
        let dot = self.dot(other);

        // if quaternions are close together use `nlerp`
        let dot_threshold = Number::from(0.9995);
        if dot > dot_threshold { return self.nlerp(other, amount) }

        let robust_dot = dot.clamp(&-Number::from(1), &Number::from(1));    // stay within the domain of acos()
        let theta_0 = acos(&robust_dot);                    // the angle between the quaternions
        let theta = theta_0 * amount;                       // the fraction of theta specified by `amount`

        let q = other.sub_q(&self.mul_t(robust_dot))
                     .normalize();

        self.mul_t(cos(&theta)).add_q(&q.mul_t(sin(&theta)))
    }

    #[inline(always)]
    pure fn to_mat3(&self) -> Mat3<T> {
        let x2 = self.v.x + self.v.x;
        let y2 = self.v.y + self.v.y;
        let z2 = self.v.z + self.v.z;

        let xx2 = x2 * self.v.x;
        let xy2 = x2 * self.v.y;
        let xz2 = x2 * self.v.z;

        let yy2 = y2 * self.v.y;
        let yz2 = y2 * self.v.z;
        let zz2 = z2 * self.v.z;

        let sy2 = y2 * self.s;
        let sz2 = z2 * self.s;
        let sx2 = x2 * self.s;

        let _1: T = Number::from(1);

        Mat3::new(_1 - yy2 - zz2,      xy2 - sz2,      xz2 + sy2,
                       xy2 + sz2, _1 - xx2 - zz2,      yz2 - sx2,
                       xz2 - sy2,      yz2 + sx2, _1 - xx2 - yy2)
    }

    #[inline(always)]
    pure fn to_mat4(&self) -> Mat4<T> {
        self.to_mat3().to_mat4()
    }
}

pub impl<T:Copy Num> Quat<T>: Neg<Quat<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Quat<T> {
        Quat::new(-self[0], -self[1], -self[2], -self[3])
    }
}

pub impl<T:Copy Eq> Quat<T>: Eq {
    #[inline(always)]
    pure fn eq(&self, other: &Quat<T>) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }

    #[inline(always)]
    pure fn ne(&self, other: &Quat<T>) -> bool {
        !(self == other)
    }
}

pub impl<T:Copy FuzzyEq> Quat<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Quat<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}<commit_msg>Fix to_mat3 method<commit_after>/**
 * > Every morning in the early part of October 1843, on my coming down to
 *   breakfast, your brother William Edward and yourself used to ask me: "Well,
 *   Papa, can you multiply triples?" Whereto I was always obliged to reply,
 *   with a sad shake of the head, "No, I can only add and subtract them."
 *
 *   Sir William Hamilton
 */

use core::cast::transmute;
use core::cmp::{Eq, Ord};
use core::ptr::to_unsafe_ptr;
use core::sys::size_of;
use core::vec::raw::buf_as_slice;

use std::cmp::FuzzyEq;

use dim::{Dimensional, ToPtr};
use funs::common::*;
use funs::exponential::*;
use funs::triganomic::*;
use mat::{Mat3, Mat4};
use num::kinds::{Float, Number};
use vec::Vec3;

/**
 * The base quaternion trait
 *
 * # Type parameters
 *
 * * `T` - The type of the components. Should be a floating point type.
 * * `V3` - The 3-dimensional vector type that will containin the imaginary
 *          components of the quaternion.
 */
pub trait Quaternion<T,V3>: Dimensional<T>, ToPtr<T>, Eq, Neg<self> {
    /**
     * # Return value
     *
     * The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
     */
    static pure fn identity() -> self;

    /**
     * # Return value
     *
     * The additive identity, ie: `q = 0 + 0i + 0j + 0i`
     */
    static pure fn zero() -> self;

    /**
     * # Return value
     *
     * The result of multiplying the quaternion a scalar
     */
    pure fn mul_t(&self, value: T) -> self;

    /**
     * # Return value
     *
     * The result of dividing the quaternion a scalar
     */
    pure fn div_t(&self, value: T) -> self;

    /**
     * # Return value
     *
     * The result of multiplying the quaternion by a vector
     */
    pure fn mul_v(&self, vec: &V3) -> V3;

    /**
     * # Return value
     *
     * The sum of this quaternion and `other`
     */
    pure fn add_q(&self, other: &self) -> self;

    /**
     * # Return value
     *
     * The sum of this quaternion and `other`
     */
    pure fn sub_q(&self, other: &self) -> self;

    /**
     * # Return value
     *
     * The the result of multipliplying the quaternion by `other`
     */
    pure fn mul_q(&self, other: &self) -> self;

    /**
     * # Return value
     *
     * The dot product of the quaternion and `other`
     */
    pure fn dot(&self, other: &self) -> T;

    /**
     * # Return value
     *
     * The conjugate of the quaternion
     */
    pure fn conjugate(&self) -> self;

    /**
     * # Return value
     *
     * The multiplicative inverse of the quaternion
     */
    pure fn inverse(&self) -> self;

    /**
     * # Return value
     *
     * The squared magnitude of the quaternion. This is useful for
     * magnitude comparisons where the exact magnitude does not need to be
     * calculated.
     */
    pure fn magnitude2(&self) -> T;

    /**
     * # Return value
     *
     * The magnitude of the quaternion
     *
     * # Performance notes
     *
     * For instances where the exact magnitude of the quaternion does not need
     * to be known, for example for quaternion-quaternion magnitude comparisons,
     * it is advisable to use the `magnitude2` method instead.
     */
    pure fn magnitude(&self) -> T;

    /**
     * # Return value
     *
     * The normalized quaternion
     */
    pure fn normalize(&self) -> self;

    /**
     * Normalised linear interpolation
     *
     * # Return value
     *
     * The intoperlated quaternion
     */
    pure fn nlerp(&self, other: &self, amount: T) -> self;

    /**
     * Perform a spherical linear interpolation between the quaternion and
     * `other`.
     *
     * # Return value
     *
     * The intoperlated quaternion
     *
     * # Performance notes
     *
     * This is more accurate than `nlerp` but is also more
     * computationally intensive.
     */
    pure fn slerp(&self, other: &self, amount: T) -> self;

    /**
     * Convert the quaternion to a 3 x 3 rotation matrix
     */
    pure fn to_mat3(&self) -> Mat3<T>;

    /**
     * Convert the quaternion to a 4 x 4 transformation matrix
     */
    pure fn to_mat4(&self) -> Mat4<T>;
}

pub trait ToQuat<T> {
    /**
     * Convert `self` to a quaternion
     */
    pure fn to_Quat() -> Quat<T>;
}

/**
 * A quaternion in scalar/vector form
 *
 * # Type parameters
 *
 * * `T` - The type of the components. Should be a floating point type.
 *
 * # Fields
 *
 * * `s` - the scalar component
 * * `v` - a vector containing the three imaginary components
 */
pub struct Quat<T> { s: T, v: Vec3<T> }

pub impl<T> Quat<T> {
    /**
     * Construct the quaternion from one scalar component and three
     * imaginary components
     *
     * # Arguments
     *
     * * `w`  - the scalar component
     * * `xi` - the fist imaginary component
     * * `yj` - the second imaginary component
     * * `zk` - the third imaginary component
     */
    #[inline(always)]
    static pure fn new(w: T, xi: T, yj: T, zk: T) -> Quat<T> {
        Quat::from_sv(move w, move Vec3::new(move xi, move yj, move zk))
    }

    /**
     * Construct the quaternion from a scalar and a vector
     *
     * # Arguments
     *
     * * `s` - the scalar component
     * * `v` - a vector containing the three imaginary components
     */
    #[inline(always)]
    static pure fn from_sv(s: T, v: Vec3<T>) -> Quat<T> {
        Quat { s: move s, v: move v }
    }
}

pub impl<T> Quat<T>: Dimensional<T> {
    #[inline(always)]
    static pure fn dim() -> uint { 4 }

    #[inline(always)]
    static pure fn size_of() -> uint { size_of::<Quat<T>>() }
}

pub impl<T:Copy> Quat<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(i: uint) -> T {
        unsafe { do buf_as_slice(self.to_ptr(), 4) |slice| { slice[i] } }
    }
}

pub impl<T:Copy> Quat<T>: ToPtr<T> {
    #[inline(always)]
    pure fn to_ptr(&self) -> *T {
        unsafe {
            transmute::<*Quat<T>, *T>(
                to_unsafe_ptr(&*self)
            )
        }
    }
}

pub impl<T:Copy Float Exp Extent InvTrig> Quat<T>: Quaternion<T, Vec3<T>> {
    #[inline(always)]
    static pure fn identity() -> Quat<T> {
        Quat::new(Number::from(1),
                  Number::from(0),
                  Number::from(0),
                  Number::from(0))
    }

    #[inline(always)]
    static pure fn zero() -> Quat<T> {
        Quat::new(Number::from(0),
                  Number::from(0),
                  Number::from(0),
                  Number::from(0))
    }

    #[inline(always)]
    pure fn mul_t(&self, value: T) -> Quat<T> {
        Quat::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(&self, value: T) -> Quat<T> {
        Quat::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn mul_v(&self, vec: &Vec3<T>) -> Vec3<T>  {
        let tmp = self.v.cross(vec).add_v(&vec.mul_t(self.s));
        self.v.cross(&tmp).mul_t(Number::from(2)).add_v(vec)
    }

    #[inline(always)]
    pure fn add_q(&self, other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_q(&self, other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_q(&self, other: &Quat<T>) -> Quat<T> {
        Quat::new(self.s * other.s   - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z,
                  self.s * other.v.x + self.v.x * other.s   + self.v.y * other.v.z - self.v.z * other.v.y,
                  self.s * other.v.y + self.v.y * other.s   + self.v.z * other.v.x - self.v.x * other.v.z,
                  self.s * other.v.z + self.v.z * other.s   + self.v.x * other.v.y - self.v.y * other.v.x)
    }

    #[inline(always)]
    pure fn dot(&self, other: &Quat<T>) -> T {
        self.s * other.s + self.v.dot(&other.v)
    }

    #[inline(always)]
    pure fn conjugate(&self) -> Quat<T> {
        Quat::from_sv(self.s, -self.v)
    }

    #[inline(always)]
    pure fn inverse(&self) -> Quat<T> {
        self.conjugate().div_t(self.magnitude2())
    }

    #[inline(always)]
    pure fn magnitude2(&self) -> T {
        self.s * self.s + self.v.length2()
    }

    #[inline(always)]
    pure fn magnitude(&self) -> T {
        self.magnitude2().sqrt()
    }

    #[inline(always)]
    pure fn normalize(&self) -> Quat<T> {
        let mut n: T = Number::from(1);
        n /= self.magnitude();
        return self.mul_t(n);
    }

    #[inline(always)]
    pure fn nlerp(&self, other: &Quat<T>, amount: T) -> Quat<T> {
        let _1: T = Number::from(1);
        self.mul_t(_1 - amount).add_q(&other.mul_t(amount)).normalize()
    }

    /**
     * Spherical Linear Intoperlation
     *
     * Both quaternions should be normalized first, or else strange things will
     * will happen...
     *
     * # Performance notes
     *
     * The `acos` operation used in `slerp` is an expensive operation, so unless
     * your quarternions a far away from each other it's generally more advisable
     * to use `nlerp` when you know your rotations are going to be small.
     *
     * - [Understanding Slerp, Then Not Using It]
     *   (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)
     * - [Arcsynthesis OpenGL tutorial]
     *   (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
     */
    #[inline(always)]
    pure fn slerp(&self, other: &Quat<T>, amount: T) -> Quat<T> {
        let dot = self.dot(other);

        // if quaternions are close together use `nlerp`
        let dot_threshold = Number::from(0.9995);
        if dot > dot_threshold { return self.nlerp(other, amount) }

        let robust_dot = dot.clamp(&-Number::from(1), &Number::from(1));    // stay within the domain of acos()
        let theta_0 = acos(&robust_dot);                    // the angle between the quaternions
        let theta = theta_0 * amount;                       // the fraction of theta specified by `amount`

        let q = other.sub_q(&self.mul_t(robust_dot))
                     .normalize();

        self.mul_t(cos(&theta)).add_q(&q.mul_t(sin(&theta)))
    }

    #[inline(always)]
    pure fn to_mat3(&self) -> Mat3<T> {
        let x2 = self.v.x + self.v.x;
        let y2 = self.v.y + self.v.y;
        let z2 = self.v.z + self.v.z;

        let xx2 = x2 * self.v.x;
        let xy2 = x2 * self.v.y;
        let xz2 = x2 * self.v.z;

        let yy2 = y2 * self.v.y;
        let yz2 = y2 * self.v.z;
        let zz2 = z2 * self.v.z;

        let sy2 = y2 * self.s;
        let sz2 = z2 * self.s;
        let sx2 = x2 * self.s;

        let _1: T = Number::from(1);

        Mat3::new(_1 - yy2 - zz2,      xy2 + sz2,      xz2 - sy2,
                       xy2 - sz2, _1 - xx2 - zz2,      yz2 + sx2,
                       xz2 + sy2,      yz2 - sx2, _1 - xx2 - yy2)
    }

    #[inline(always)]
    pure fn to_mat4(&self) -> Mat4<T> {
        self.to_mat3().to_mat4()
    }
}

pub impl<T:Copy Num> Quat<T>: Neg<Quat<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Quat<T> {
        Quat::new(-self[0], -self[1], -self[2], -self[3])
    }
}

pub impl<T:Copy Eq> Quat<T>: Eq {
    #[inline(always)]
    pure fn eq(&self, other: &Quat<T>) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }

    #[inline(always)]
    pure fn ne(&self, other: &Quat<T>) -> bool {
        !(self == other)
    }
}

pub impl<T:Copy FuzzyEq> Quat<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Quat<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}<|endoftext|>


<commit_before>use num_complex::Complex;
use num_traits::Float;
use std::slice::from_raw_parts_mut;

use {Operation, Plan, Transform};

impl<T> Transform<T> for [T] where T: Float {
    fn transform(&mut self, plan: &Plan<T>) {
        let n = self.len();
        assert!(n == plan.n);
        let h = n >> 1;
        if h == 0 {
            return;
        }
        let data = unsafe { from_raw_parts_mut(self.as_mut_ptr() as *mut _, h) };
        match plan.operation {
            Operation::Forward => {
                data.transform(plan);
                compose(data, h, &plan.factors, false);
            },
            Operation::Backward | Operation::Inverse => {
                compose(data, h, &plan.factors, true);
                data.transform(plan);
            },
        }
    }
}

impl<T> Transform<T> for Vec<T> where T: Float {
    #[inline(always)]
    fn transform(&mut self, plan: &Plan<T>) {
        Transform::transform(&mut self[..], plan)
    }
}

/// Unpack the result produced by the forward transform applied to real data.
///
/// The function decodes the result of an application of `Transform::transform`
/// with `Operation::Forward` to real data. See the top-level description of the
/// crate for further details.
pub fn unpack<T>(data: &[T]) -> Vec<Complex<T>> where T: Float {
    let n = data.len();
    assert!(n.is_power_of_two());
    let h = n >> 1;
    let mut result = Vec::with_capacity(n);
    unsafe { result.set_len(n) };
    result[0] = data[0].into();
    if h == 0 {
        return result;
    }
    for i in 1..h {
        result[i] = Complex::new(data[2 * i], data[2 * i + 1]);
    }
    result[h] = data[1].into();
    for i in (h + 1)..n {
        result[i] = result[n - i].conj();
    }
    result
}

#[inline(always)]
fn compose<T>(data: &mut [Complex<T>], n: usize, factors: &[Complex<T>], inverse: bool)
    where T: Float
{
    let one = T::one();
    let half = (one + one).recip();
    let h = n >> 1;
    data[0] = Complex::new(data[0].re + data[0].im, data[0].re - data[0].im);
    if inverse {
        data[0] = data[0].scale(half);
    }
    if h == 0 {
        return;
    }
    let m = factors.len();
    let sign = if inverse { Complex::i() } else { -Complex::i() };
    for i in 1..h {
        let j = n - i;
        let part1 = data[i] + data[j].conj();
        let part2 = data[i] - data[j].conj();
        let product = sign * factors[m - j] * part2;
        data[i] = (part1 + product).scale(half);
        data[j] = (part1 - product).scale(half).conj();
    }
    data[h] = data[h].conj();
}

#[cfg(test)]
mod tests {
    use c64;

    #[test]
    fn unpack() {
        let data = (0..4).map(|i| (i + 1) as f64).collect::<Vec<_>>();
        assert_eq!(super::unpack(&data), vec![
            c64::new(1.0, 0.0), c64::new(3.0, 4.0), c64::new(2.0, 0.0), c64::new(3.0, -4.0),
        ]);

        let data = (0..8).map(|i| (i + 1) as f64).collect::<Vec<_>>();
        assert_eq!(super::unpack(&data), vec![
            c64::new(1.0, 0.0), c64::new(3.0,  4.0), c64::new(5.0,  6.0), c64::new(7.0,  8.0),
            c64::new(2.0, 0.0), c64::new(7.0, -8.0), c64::new(5.0, -6.0), c64::new(3.0, -4.0),
        ]);
    }
}
<commit_msg>sign was not having its type derived explicitely which was causing issues during compilation.<commit_after>use num_complex::Complex;
use num_traits::Float;
use std::slice::from_raw_parts_mut;

use {Operation, Plan, Transform};

impl<T> Transform<T> for [T] where T: Float {
    fn transform(&mut self, plan: &Plan<T>) {
        let n = self.len();
        assert!(n == plan.n);
        let h = n >> 1;
        if h == 0 {
            return;
        }
        let data = unsafe { from_raw_parts_mut(self.as_mut_ptr() as *mut _, h) };
        match plan.operation {
            Operation::Forward => {
                data.transform(plan);
                compose(data, h, &plan.factors, false);
            },
            Operation::Backward | Operation::Inverse => {
                compose(data, h, &plan.factors, true);
                data.transform(plan);
            },
        }
    }
}

impl<T> Transform<T> for Vec<T> where T: Float {
    #[inline(always)]
    fn transform(&mut self, plan: &Plan<T>) {
        Transform::transform(&mut self[..], plan)
    }
}

/// Unpack the result produced by the forward transform applied to real data.
///
/// The function decodes the result of an application of `Transform::transform`
/// with `Operation::Forward` to real data. See the top-level description of the
/// crate for further details.
pub fn unpack<T>(data: &[T]) -> Vec<Complex<T>> where T: Float {
    let n = data.len();
    assert!(n.is_power_of_two());
    let h = n >> 1;
    let mut result = Vec::with_capacity(n);
    unsafe { result.set_len(n) };
    result[0] = data[0].into();
    if h == 0 {
        return result;
    }
    for i in 1..h {
        result[i] = Complex::new(data[2 * i], data[2 * i + 1]);
    }
    result[h] = data[1].into();
    for i in (h + 1)..n {
        result[i] = result[n - i].conj();
    }
    result
}

#[inline(always)]
fn compose<T>(data: &mut [Complex<T>], n: usize, factors: &[Complex<T>], inverse: bool)
    where T: Float
{
    let one = T::one();
    let half = (one + one).recip();
    let h = n >> 1;
    data[0] = Complex::new(data[0].re + data[0].im, data[0].re - data[0].im);
    if inverse {
        data[0] = data[0].scale(half);
    }
    if h == 0 {
        return;
    }
    let m = factors.len();
    let sign : Complex<T> = if inverse { Complex::i() } else { -Complex::i() };
    for i in 1..h {
        let j = n - i;
        let part1 = data[i] + data[j].conj();
        let part2 = data[i] - data[j].conj();
        let product = sign * factors[m - j] * part2;
        data[i] = (part1 + product).scale(half);
        data[j] = (part1 - product).scale(half).conj();
    }
    data[h] = data[h].conj();
}

#[cfg(test)]
mod tests {
    use c64;

    #[test]
    fn unpack() {
        let data = (0..4).map(|i| (i + 1) as f64).collect::<Vec<_>>();
        assert_eq!(super::unpack(&data), vec![
            c64::new(1.0, 0.0), c64::new(3.0, 4.0), c64::new(2.0, 0.0), c64::new(3.0, -4.0),
        ]);

        let data = (0..8).map(|i| (i + 1) as f64).collect::<Vec<_>>();
        assert_eq!(super::unpack(&data), vec![
            c64::new(1.0, 0.0), c64::new(3.0,  4.0), c64::new(5.0,  6.0), c64::new(7.0,  8.0),
            c64::new(2.0, 0.0), c64::new(7.0, -8.0), c64::new(5.0, -6.0), c64::new(3.0, -4.0),
        ]);
    }
}
<|endoftext|>


<commit_before>use super::{Buf, MutBuf};
use std::{cmp, fmt, mem, ptr, slice};
use std::rt::heap;

/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
/// write cursor. When reads and writes reach the end of the allocated buffer,
/// wraps around to the start.
pub struct RingBuf {
    ptr: *mut u8,  // Pointer to the memory
    cap: usize,     // Capacity of the buffer
    pos: usize,     // Offset of read cursor
    len: usize      // Number of bytes to read
}

// TODO: There are most likely many optimizations that can be made
impl RingBuf {
    pub fn new(mut capacity: usize) -> RingBuf {
        // Handle the 0 length buffer case
        if capacity == 0 {
            return RingBuf {
                ptr: ptr::null_mut(),
                cap: 0,
                pos: 0,
                len: 0
            }
        }

        // Round to the next power of 2 for better alignment
        capacity = capacity.next_power_of_two();

        // Allocate the memory
        let ptr = unsafe { heap::allocate(capacity, mem::min_align_of::<u8>()) };

        RingBuf {
            ptr: ptr as *mut u8,
            cap: capacity,
            pos: 0,
            len: 0
        }
    }

    pub fn is_full(&self) -> bool {
        self.cap == self.len
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn capacity(&self) -> usize {
        self.cap
    }

    fn read_remaining(&self) -> usize {
        self.len
    }

    fn write_remaining(&self) -> usize {
        self.cap - self.len
    }

    fn advance_reader(&mut self, mut cnt: usize) {
        cnt = cmp::min(cnt, self.read_remaining());

        self.pos += cnt;
        self.pos %= self.cap;
        self.len -= cnt;
    }

    fn advance_writer(&mut self, mut cnt: usize) {
        cnt = cmp::min(cnt, self.write_remaining());
        self.len += cnt;
    }

    fn as_slice(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.ptr as *const u8, self.cap)
        }
    }

    fn as_mut_slice(&mut self) -> &mut [u8] {
        unsafe {
            slice::from_raw_parts_mut(self.ptr, self.cap)
        }
    }
}

impl Clone for RingBuf {
    fn clone(&self) -> RingBuf {
        use std::cmp;

        let mut ret = RingBuf::new(self.cap);

        ret.pos = self.pos;
        ret.len = self.len;

        unsafe {
            let to = self.pos + self.len;

            if to > self.cap {
                ptr::copy(ret.ptr, self.ptr as *const u8, to % self.cap);
            }

            ptr::copy(
                ret.ptr.offset(self.pos as isize),
                self.ptr.offset(self.pos as isize) as *const u8,
                cmp::min(self.len, self.cap - self.pos));
        }

        ret
    }

    // TODO: an improved version of clone_from is possible that potentially
    // re-uses the buffer
}

impl fmt::Debug for RingBuf {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "RingBuf[.. {}]", self.len)
    }
}

impl Drop for RingBuf {
    fn drop(&mut self) {
        if self.cap > 0 {
            unsafe {
                heap::deallocate(self.ptr, self.cap, mem::min_align_of::<u8>())
            }
        }
    }
}

impl Buf for RingBuf {

    fn remaining(&self) -> usize {
        self.read_remaining()
    }

    fn bytes(&self) -> &[u8] {
        let mut to = self.pos + self.len;

        if to > self.cap {
            to = self.cap
        }

        &self.as_slice()[self.pos .. to]
    }

    fn advance(&mut self, cnt: usize) {
        self.advance_reader(cnt)
    }
}

impl MutBuf for RingBuf {

    fn remaining(&self) -> usize {
        self.write_remaining()
    }

    fn advance(&mut self, cnt: usize) {
        self.advance_writer(cnt)
    }

    fn mut_bytes(&mut self) -> &mut [u8] {
        let mut from;
        let mut to;

        from = self.pos + self.len;
        from %= self.cap;

        to = from + <Self as MutBuf>::remaining(&self);

        if to >= self.cap {
            to = self.cap;
        }

        &mut self.as_mut_slice()[from..to]
    }
}

unsafe impl Send for RingBuf { }
<commit_msg>Fix panics on operations on 0-capacity RingBuf<commit_after>use super::{Buf, MutBuf};
use std::{cmp, fmt, mem, ptr, slice};
use std::rt::heap;

/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
/// write cursor. When reads and writes reach the end of the allocated buffer,
/// wraps around to the start.
pub struct RingBuf {
    ptr: *mut u8,  // Pointer to the memory
    cap: usize,     // Capacity of the buffer
    pos: usize,     // Offset of read cursor
    len: usize      // Number of bytes to read
}

// TODO: There are most likely many optimizations that can be made
impl RingBuf {
    pub fn new(mut capacity: usize) -> RingBuf {
        // Handle the 0 length buffer case
        if capacity == 0 {
            return RingBuf {
                ptr: ptr::null_mut(),
                cap: 0,
                pos: 0,
                len: 0
            }
        }

        // Round to the next power of 2 for better alignment
        capacity = capacity.next_power_of_two();

        // Allocate the memory
        let ptr = unsafe { heap::allocate(capacity, mem::min_align_of::<u8>()) };

        RingBuf {
            ptr: ptr as *mut u8,
            cap: capacity,
            pos: 0,
            len: 0
        }
    }

    pub fn is_full(&self) -> bool {
        self.cap == self.len
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn capacity(&self) -> usize {
        self.cap
    }

    fn read_remaining(&self) -> usize {
        self.len
    }

    fn write_remaining(&self) -> usize {
        self.cap - self.len
    }

    fn advance_reader(&mut self, mut cnt: usize) {
        if self.cap == 0 {
            return;
        }
        cnt = cmp::min(cnt, self.read_remaining());

        self.pos += cnt;
        self.pos %= self.cap;
        self.len -= cnt;
    }

    fn advance_writer(&mut self, mut cnt: usize) {
        cnt = cmp::min(cnt, self.write_remaining());
        self.len += cnt;
    }

    fn as_slice(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.ptr as *const u8, self.cap)
        }
    }

    fn as_mut_slice(&mut self) -> &mut [u8] {
        unsafe {
            slice::from_raw_parts_mut(self.ptr, self.cap)
        }
    }
}

impl Clone for RingBuf {
    fn clone(&self) -> RingBuf {
        use std::cmp;

        let mut ret = RingBuf::new(self.cap);

        ret.pos = self.pos;
        ret.len = self.len;

        unsafe {
            let to = self.pos + self.len;

            if to > self.cap {
                ptr::copy(ret.ptr, self.ptr as *const u8, to % self.cap);
            }

            ptr::copy(
                ret.ptr.offset(self.pos as isize),
                self.ptr.offset(self.pos as isize) as *const u8,
                cmp::min(self.len, self.cap - self.pos));
        }

        ret
    }

    // TODO: an improved version of clone_from is possible that potentially
    // re-uses the buffer
}

impl fmt::Debug for RingBuf {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "RingBuf[.. {}]", self.len)
    }
}

impl Drop for RingBuf {
    fn drop(&mut self) {
        if self.cap > 0 {
            unsafe {
                heap::deallocate(self.ptr, self.cap, mem::min_align_of::<u8>())
            }
        }
    }
}

impl Buf for RingBuf {

    fn remaining(&self) -> usize {
        self.read_remaining()
    }

    fn bytes(&self) -> &[u8] {
        let mut to = self.pos + self.len;

        if to > self.cap {
            to = self.cap
        }

        &self.as_slice()[self.pos .. to]
    }

    fn advance(&mut self, cnt: usize) {
        self.advance_reader(cnt)
    }
}

impl MutBuf for RingBuf {

    fn remaining(&self) -> usize {
        self.write_remaining()
    }

    fn advance(&mut self, cnt: usize) {
        self.advance_writer(cnt)
    }

    fn mut_bytes(&mut self) -> &mut [u8] {
        if self.cap == 0 {
            return self.as_mut_slice();
        }
        let mut from;
        let mut to;

        from = self.pos + self.len;
        from %= self.cap;

        to = from + <Self as MutBuf>::remaining(&self);

        if to >= self.cap {
            to = self.cap;
        }

        &mut self.as_mut_slice()[from..to]
    }
}

unsafe impl Send for RingBuf { }
<|endoftext|>


<commit_before>use std::default::Default;
use std::ffi::OsStr;
use std::fs;
use std::io::Read;
use std::path;

use liquid;
use serde_json;
use serde_yaml;
use toml;

use error::*;
use files;

const DATA_DIR: &'static str = "_data";

#[derive(Debug, PartialEq, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SiteBuilder {
    pub name: Option<String>,
    pub description: Option<String>,
    pub base_url: Option<String>,
    #[serde(skip)]
    pub data_dir: &'static str,
}

impl Default for SiteBuilder {
    fn default() -> SiteBuilder {
        SiteBuilder {
            name: None,
            description: None,
            base_url: None,
            data_dir: DATA_DIR,
        }
    }
}

impl SiteBuilder {
    pub fn build(self, root: &path::Path) -> Result<Site> {
        let SiteBuilder {
            name,
            description,
            base_url,
            data_dir,
        } = self;
        let base_url = base_url.map(|mut l| {
                                        if l.ends_with('/') {
                                            l.pop();
                                        }
                                        l
                                    });

        let mut attributes = liquid::Object::new();
        if let Some(ref name) = name {
            attributes.insert("name".to_owned(), liquid::Value::str(name));
        }
        if let Some(ref description) = description {
            attributes.insert("description".to_owned(), liquid::Value::str(description));
        }
        if let Some(ref base_url) = base_url {
            attributes.insert("base_url".to_owned(), liquid::Value::str(base_url));
        }
        let mut data = liquid::Object::new();
        insert_data_dir(&mut data, &root.join(data_dir))?;
        if !data.is_empty() {
            attributes.insert("data".to_owned(), liquid::Value::Object(data));
        }

        Ok(Site {
               name,
               description,
               base_url,
               attributes,
           })
    }
}

#[derive(Debug, PartialEq, Default, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Site {
    pub name: Option<String>,
    pub description: Option<String>,
    pub base_url: Option<String>,
    pub attributes: liquid::Object,
}

fn deep_insert(data_map: &mut liquid::Object,
               file_path: &path::Path,
               target_key: String,
               data: liquid::Value)
               -> Result<()> {
    // now find the nested map it is supposed to be in
    let target_map = if let Some(path) = file_path.parent() {
        let mut map = data_map;
        for part in path.iter() {
            let key = part.to_str().ok_or_else(|| {
                format!("The data from {:?} can't be loaded as it contains non utf-8 characters",
                        path)
            })?;
            let cur_map = map;
            map = cur_map
                .entry(String::from(key))
                .or_insert_with(|| liquid::Value::Object(liquid::Object::new()))
                .as_object_mut()
                .ok_or_else(|| {
                                format!("Aborting: Duplicate in data tree. Would overwrite {:?} ",
                                        path)
                            })?;
        }
        map
    } else {
        data_map
    };

    match target_map.insert(target_key, data) {
        None => Ok(()),
        _ => {
            Err(format!("The data from {:?} can't be loaded: the key already exists",
                        file_path)
                    .into())
        }
    }
}

fn load_data(data_path: &path::Path) -> Result<liquid::Value> {
    let ext = data_path.extension().unwrap_or_else(|| OsStr::new(""));

    let data: liquid::Value;

    if ext == OsStr::new("yml") || ext == OsStr::new("yaml") {
        let reader = fs::File::open(data_path)?;
        data = serde_yaml::from_reader(reader)?;
    } else if ext == OsStr::new("json") {
        let reader = fs::File::open(data_path)?;
        data = serde_json::from_reader(reader)?;
    } else if ext == OsStr::new("toml") {
        let mut reader = fs::File::open(data_path)?;
        let mut text = String::new();
        reader.read_to_string(&mut text)?;
        data = toml::from_str(&text)?;
    } else {
        bail!("Failed to load of data {:?}: unknown file type '{:?}'.\n\
              Supported data files extensions are: yml, yaml, json and toml.",
              data_path,
              ext);
    }

    Ok(data)
}

fn insert_data_dir(data: &mut liquid::Object, data_root: &path::Path) -> Result<()> {
    let data_files_builder = files::FilesBuilder::new(data_root)?;
    let data_files = data_files_builder.build()?;
    for df in data_files.files() {
        let file_stem = df.file_stem()
            .expect("Files will always return with a stem");
        let file_stem = String::from(file_stem.to_str().unwrap());

        let full_path = data_root.join(df.clone());

        let data_fragment = load_data(&full_path)?;

        deep_insert(data, &df, file_stem, data_fragment)?;
    }

    Ok(())
}
<commit_msg>feat(config): Specify data directly in config<commit_after>use std::default::Default;
use std::ffi::OsStr;
use std::fs;
use std::io::Read;
use std::path;

use liquid;
use serde_json;
use serde_yaml;
use toml;

use error::*;
use files;

const DATA_DIR: &'static str = "_data";

#[derive(Debug, PartialEq, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SiteBuilder {
    pub name: Option<String>,
    pub description: Option<String>,
    pub base_url: Option<String>,
    pub data: Option<liquid::Object>,
    #[serde(skip)]
    pub data_dir: &'static str,
}

impl Default for SiteBuilder {
    fn default() -> SiteBuilder {
        SiteBuilder {
            name: None,
            description: None,
            base_url: None,
            data: None,
            data_dir: DATA_DIR,
        }
    }
}

impl SiteBuilder {
    pub fn build(self, root: &path::Path) -> Result<Site> {
        let SiteBuilder {
            name,
            description,
            base_url,
            data,
            data_dir,
        } = self;
        let base_url = base_url.map(|mut l| {
                                        if l.ends_with('/') {
                                            l.pop();
                                        }
                                        l
                                    });

        let mut attributes = liquid::Object::new();
        if let Some(ref name) = name {
            attributes.insert("name".to_owned(), liquid::Value::str(name));
        }
        if let Some(ref description) = description {
            attributes.insert("description".to_owned(), liquid::Value::str(description));
        }
        if let Some(ref base_url) = base_url {
            attributes.insert("base_url".to_owned(), liquid::Value::str(base_url));
        }
        let mut data = data.unwrap_or_default();
        insert_data_dir(&mut data, &root.join(data_dir))?;
        if !data.is_empty() {
            attributes.insert("data".to_owned(), liquid::Value::Object(data));
        }

        Ok(Site {
               name,
               description,
               base_url,
               attributes,
           })
    }
}

#[derive(Debug, PartialEq, Default, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Site {
    pub name: Option<String>,
    pub description: Option<String>,
    pub base_url: Option<String>,
    pub attributes: liquid::Object,
}

fn deep_insert(data_map: &mut liquid::Object,
               file_path: &path::Path,
               target_key: String,
               data: liquid::Value)
               -> Result<()> {
    // now find the nested map it is supposed to be in
    let target_map = if let Some(path) = file_path.parent() {
        let mut map = data_map;
        for part in path.iter() {
            let key = part.to_str().ok_or_else(|| {
                format!("The data from {:?} can't be loaded as it contains non utf-8 characters",
                        path)
            })?;
            let cur_map = map;
            map = cur_map
                .entry(String::from(key))
                .or_insert_with(|| liquid::Value::Object(liquid::Object::new()))
                .as_object_mut()
                .ok_or_else(|| {
                                format!("Aborting: Duplicate in data tree. Would overwrite {:?} ",
                                        path)
                            })?;
        }
        map
    } else {
        data_map
    };

    match target_map.insert(target_key, data) {
        None => Ok(()),
        _ => {
            Err(format!("The data from {:?} can't be loaded: the key already exists",
                        file_path)
                    .into())
        }
    }
}

fn load_data(data_path: &path::Path) -> Result<liquid::Value> {
    let ext = data_path.extension().unwrap_or_else(|| OsStr::new(""));

    let data: liquid::Value;

    if ext == OsStr::new("yml") || ext == OsStr::new("yaml") {
        let reader = fs::File::open(data_path)?;
        data = serde_yaml::from_reader(reader)?;
    } else if ext == OsStr::new("json") {
        let reader = fs::File::open(data_path)?;
        data = serde_json::from_reader(reader)?;
    } else if ext == OsStr::new("toml") {
        let mut reader = fs::File::open(data_path)?;
        let mut text = String::new();
        reader.read_to_string(&mut text)?;
        data = toml::from_str(&text)?;
    } else {
        bail!("Failed to load of data {:?}: unknown file type '{:?}'.\n\
              Supported data files extensions are: yml, yaml, json and toml.",
              data_path,
              ext);
    }

    Ok(data)
}

fn insert_data_dir(data: &mut liquid::Object, data_root: &path::Path) -> Result<()> {
    let data_files_builder = files::FilesBuilder::new(data_root)?;
    let data_files = data_files_builder.build()?;
    for df in data_files.files() {
        let file_stem = df.file_stem()
            .expect("Files will always return with a stem");
        let file_stem = String::from(file_stem.to_str().unwrap());

        let full_path = data_root.join(df.clone());

        let data_fragment = load_data(&full_path)?;

        deep_insert(data, &df, file_stem, data_fragment)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use glm;
use moho::errors::*;
use moho::resource_manager::{Renderer, ResourceManager, TextureData};

use animation::Animation;
use circle::Circle;
use collidable::Collidable;
use shape::Intersect;

use std::cmp;
use std::time::Duration;

pub enum State {
    INACTIVE,
    ACTIVE,
    EXPLODED,
}

pub struct Star<R: Renderer> {
    state: State,
    body: Circle,
    texture: TextureData<R>,
    explosion_texture: TextureData<R>,
    animation: Animation,
    explosion_animation: Animation,
}

impl<R: Renderer> Star<R> {
    pub fn new(center: glm::IVec2, resource_manager: &ResourceManager<R>) -> Result<Self> {
        let mut texture = resource_manager.load_texture("resources/star.png")?;
        let mut explosion_texture = resource_manager.load_texture("resources/explosion_small.png")?;
        let star_duration = Duration::from_millis(150);
        let explosion_duration = Duration::from_millis(100);
        let animation = Animation::new(2, star_duration, texture.dims, true);
        let explosion_animation =
            Animation::new(10, explosion_duration, explosion_texture.dims, false);
        let radius = cmp::max(texture.dims.x, texture.dims.y) as f64 / 2.;
        texture.dims.x /= 2;
        explosion_texture.dims.x /= 10;
        let body = Circle {
            center: glm::to_dvec2(center),
            radius: radius,
        };

        let star = Star {
            state: State::ACTIVE,
            body: body,
            texture: texture,
            explosion_texture: explosion_texture,
            animation: animation,
            explosion_animation: explosion_animation,
        };

        Ok(star)
    }

    pub fn explode(&mut self) {
        self.state = State::EXPLODED;
    }

    pub fn update(&mut self) {
        match self.state {
            State::INACTIVE => {}
            State::ACTIVE => self.animation.update(),
            State::EXPLODED => {
                self.explosion_animation.update();
                if !self.explosion_animation.is_active() {
                    self.state = State::INACTIVE;
                }
            }
        }
    }

    pub fn draw(&self, renderer: &mut ResourceManager<R>) -> Result<()> {
        match self.state {
            State::INACTIVE => Ok(()),
            State::ACTIVE => self.draw_star(renderer),
            State::EXPLODED => self.draw_explosion(renderer),
        }
    }

    fn draw_star(&self, renderer: &mut ResourceManager<R>) -> Result<()> {
        let src_rect = self.animation.src_rect();
        self.draw_on_center(&self.texture, src_rect, renderer)
    }

    fn draw_explosion(&self, renderer: &mut ResourceManager<R>) -> Result<()> {
        let src_rect = self.explosion_animation.src_rect();
        self.draw_on_center(&self.explosion_texture, src_rect, renderer)
    }

    fn draw_on_center(&self,
                      texture: &TextureData<R>,
                      src_rect: glm::IVec4,
                      renderer: &mut ResourceManager<R>)
                      -> Result<()> {
        let center = glm::to_ivec2(self.body.center);
        renderer.draw_from_center(texture, center, Some(src_rect), None)
    }
}

impl<R: Renderer, I: Intersect<Circle>> Collidable<Circle, I> for Star<R> {
    fn collides(&self, collision: &I) -> bool {
        collision.intersects(&self.body)
    }
}
<commit_msg>small retouches on star draw<commit_after>use glm;
use moho::errors::*;
use moho::resource_manager::{Renderer, ResourceManager, TextureData};

use animation::Animation;
use circle::Circle;
use collidable::Collidable;
use shape::Intersect;

use std::cmp;
use std::time::Duration;

pub enum State {
    INACTIVE,
    ACTIVE,
    EXPLODED,
}

pub struct Star<R: Renderer> {
    state: State,
    body: Circle,
    texture: TextureData<R>,
    explosion_texture: TextureData<R>,
    animation: Animation,
    explosion_animation: Animation,
}

impl<R: Renderer> Star<R> {
    pub fn new(center: glm::IVec2, resource_manager: &ResourceManager<R>) -> Result<Self> {
        let mut texture = resource_manager.load_texture("resources/star.png")?;
        let mut explosion_texture = resource_manager.load_texture("resources/explosion_small.png")?;
        let star_duration = Duration::from_millis(150);
        let explosion_duration = Duration::from_millis(100);
        let animation = Animation::new(2, star_duration, texture.dims, true);
        let explosion_animation =
            Animation::new(10, explosion_duration, explosion_texture.dims, false);
        let radius = cmp::max(texture.dims.x, texture.dims.y) as f64 / 2.;
        texture.dims.x /= 2;
        explosion_texture.dims.x /= 10;
        let body = Circle {
            center: glm::to_dvec2(center),
            radius: radius,
        };

        let star = Star {
            state: State::ACTIVE,
            body: body,
            texture: texture,
            explosion_texture: explosion_texture,
            animation: animation,
            explosion_animation: explosion_animation,
        };

        Ok(star)
    }

    pub fn explode(&mut self) {
        self.state = State::EXPLODED;
    }

    pub fn update(&mut self) {
        match self.state {
            State::INACTIVE => {}
            State::ACTIVE => self.animation.update(),
            State::EXPLODED => {
                self.explosion_animation.update();
                if !self.explosion_animation.is_active() {
                    self.state = State::INACTIVE;
                }
            }
        }
    }

    pub fn draw(&self, renderer: &mut ResourceManager<R>) -> Result<()> {
        match self.state {
            State::INACTIVE => Ok(()),
            State::ACTIVE => {
                let src_rect = self.animation.src_rect();
                self.draw_on_center(&self.texture, src_rect, renderer)
            }
            State::EXPLODED => {
                let src_rect = self.explosion_animation.src_rect();
                self.draw_on_center(&self.explosion_texture, src_rect, renderer)
            }
        }
    }

    fn draw_on_center(&self,
                      texture: &TextureData<R>,
                      src_rect: glm::IVec4,
                      renderer: &mut ResourceManager<R>)
                      -> Result<()> {
        let center = glm::to_ivec2(self.body.center);
        renderer.draw_from_center(texture, center, Some(src_rect), None)
    }
}

impl<R: Renderer, I: Intersect<Circle>> Collidable<Circle, I> for Star<R> {
    fn collides(&self, collision: &I) -> bool {
        collision.intersects(&self.body)
    }
}
<|endoftext|>


<commit_before>use msgpack::ValueRef;
use msgpack::encode::value_ref::write_value_ref;

#[test]
fn pack_nil() {
    let mut buf = [0x00];

    let val = ValueRef::Nil;

    write_value_ref(&mut &mut buf[..], &val).unwrap();

    assert_eq!([0xc0], buf);
}
<commit_msg>UT: tested writing into a too small buffer.<commit_after>use msgpack::ValueRef;
use msgpack::encode::value_ref::write_value_ref;

#[test]
fn pack_nil() {
    let mut buf = [0x00];

    let val = ValueRef::Nil;

    write_value_ref(&mut &mut buf[..], &val).unwrap();

    assert_eq!([0xc0], buf);
}

#[test]
fn pack_nil_when_buffer_is_tool_small() {
    let mut buf = [];

    let val = ValueRef::Nil;

    match write_value_ref(&mut &mut buf[..], &val) {
        Err(..) => (),
        other => panic!("unexpected result: {:?}", other)
    }
}
<|endoftext|>


<commit_before>use rusqlite::{Connection, Error};
use quotes::Quote;

// SQL to create the quotes table in the database
//
const DATABASE_INIT_SQL: &'static str =
" CREATE TABLE quotes (
    id          INTEGER PRIMARY KEY,
    quote       TEXT NOT NULL,
    author      VARCHAR(255),
    source      TEXT
)";

const DATABASE_INSERT_QUOTE_SQL: &'static str =
" INSERT INTO quotes (quote, author, source) VALUES (?1, ?2, ?3)";

const DATABASE_QUERY_ALL_SQL: &'static str =
" SELECT * FROM quotes ";

pub fn get_database_connection(location: String) -> Result<Connection, Error> {
    let connection: Connection;
    if location == ":memory:" {
        connection = Connection::open_in_memory()?;
    } else {
        connection = Connection::open(location)?;
    }
    return Ok(connection);
}

pub fn initialize(connection: &mut Connection) -> Result<(), Error> {
    connection.execute(DATABASE_INIT_SQL, &[])?;
    Ok(())
}

pub fn add_quote(connection: &mut Connection, quote: &Quote) -> Result<(), Error> {
    connection.execute(DATABASE_INSERT_QUOTE_SQL, &[&quote.0, &quote.1, &quote.2])?;
    Ok(())
}

pub fn get_quotes(connection: &mut Connection) -> Result<Vec<Quote>, Error> {
    let mut statement = connection.prepare(DATABASE_QUERY_ALL_SQL)?;
    let mut maybe_quotes_iter = statement.query_map(&[], |row| {
        (row.get::<_, String>(1), row.get::<_, String>(2), row.get::<_, Option<String>>(3))
    })?;

    let mut quotes = Vec::new();
    for quote in maybe_quotes_iter {
        quotes.push(quote.unwrap());
    }

    return Ok(quotes)
}
<commit_msg>Remove unnecessary mutability in get_quotes()<commit_after>use rusqlite::{Connection, Error};
use quotes::Quote;

// SQL to create the quotes table in the database
//
const DATABASE_INIT_SQL: &'static str =
" CREATE TABLE quotes (
    id          INTEGER PRIMARY KEY,
    quote       TEXT NOT NULL,
    author      VARCHAR(255),
    source      TEXT
)";

const DATABASE_INSERT_QUOTE_SQL: &'static str =
" INSERT INTO quotes (quote, author, source) VALUES (?1, ?2, ?3)";

const DATABASE_QUERY_ALL_SQL: &'static str =
" SELECT * FROM quotes ";

pub fn get_database_connection(location: String) -> Result<Connection, Error> {
    let connection: Connection;
    if location == ":memory:" {
        connection = Connection::open_in_memory()?;
    } else {
        connection = Connection::open(location)?;
    }
    return Ok(connection);
}

pub fn initialize(connection: &mut Connection) -> Result<(), Error> {
    connection.execute(DATABASE_INIT_SQL, &[])?;
    Ok(())
}

pub fn add_quote(connection: &mut Connection, quote: &Quote) -> Result<(), Error> {
    connection.execute(DATABASE_INSERT_QUOTE_SQL, &[&quote.0, &quote.1, &quote.2])?;
    Ok(())
}

pub fn get_quotes(connection: &mut Connection) -> Result<Vec<Quote>, Error> {
    let mut statement = connection.prepare(DATABASE_QUERY_ALL_SQL)?;
    let maybe_quotes_iter = statement.query_map(&[], |row| {
        (row.get::<_, String>(1), row.get::<_, String>(2), row.get::<_, Option<String>>(3))
    })?;

    let mut quotes = Vec::new();
    for quote in maybe_quotes_iter {
        quotes.push(quote.unwrap());
    }

    return Ok(quotes)
}
<|endoftext|>


<commit_before>use std::net::{TcpStream,Ipv4Addr};
use metainfo::Metainfo;
use tracker_response::Peer;
use std::io::{Write, Read, Bytes};

pub fn download(info: &Metainfo, peers: &[Peer]){
	for peer in peers{
		if peer.ip != Ipv4Addr::new(207,251 ,103 ,46){
			println!("Trying with {} at port {}",peer.ip, peer.port);
			match TcpStream::connect((peer.ip, peer.port)){

				Ok(mut conn) => {
					handshake(&mut conn, &info.info_hash);
				}
				Err(_) => println!("It failed!")
			}
		}
	}
}

fn handshake(conn: &mut TcpStream, info_hash: &[u8]){
	send_handshake(conn, info_hash);
	receive_handshake(conn);
}

fn send_handshake(conn: &mut TcpStream, info_hash: &[u8]){
	let mut message = vec![];
	message.push(19);
	message.extend("BitTorrent protocol".as_bytes().iter().cloned());
	message.push(0);
	message.push(0);
	message.push(0);
	message.push(0);
	message.push(0);
	message.push(0);
	message.push(0);
	message.push(0);
	message.extend(info_hash.iter().cloned());
	message.extend("-TZ-0000-00000000001".as_bytes().iter().cloned());
	conn.write_all(&message).unwrap();
}

fn receive_handshake(conn: &mut TcpStream){
 	let inbound_bytes = &mut conn.bytes();
 	let pstrlen = read_bytes(inbound_bytes, 1);
 	let pstr = read_bytes(inbound_bytes, pstrlen[0]);
 	let reserved = read_bytes(inbound_bytes, 8);
 	let info_hash = read_bytes(inbound_bytes, 20);
 	let peer_id = read_bytes(inbound_bytes, 20);
}

fn read_bytes(byte_iter: &mut Bytes<&mut TcpStream>, n: u8) -> Vec<u8> {
	let mut out = vec![];
	for _ in 0..n  {
		let byte = byte_iter.next().unwrap().unwrap();
		out.push(byte);
	}
	out
}<commit_msg>Refactored client connection logic into struct.<commit_after>use std::net::{TcpStream,Ipv4Addr};
use metainfo::Metainfo;
use tracker_response::Peer;
use std::io::{Write, Read};

pub fn download(info: &Metainfo, peers: &[Peer]) {
    for peer in peers {
        if peer.ip != Ipv4Addr::new(207, 251, 103, 46) {
            PeerConnection::connect(peer, &info.info_hash);
        }
    }
}

struct PeerConnection {
    stream: TcpStream,
}

impl PeerConnection {
    fn connect(peer: &Peer, info_hash: &[u8]) -> Option<PeerConnection> {
        println!("Connecting to {}:{}", peer.ip, peer.port);
        match TcpStream::connect((peer.ip, peer.port)) {
            Ok(stream) => {
                let mut conn = PeerConnection { stream: stream };
                conn.handshake(info_hash);
                Some(conn)
            },
            Err(_) => {
                println!("Failed to connect to {}:{}", peer.ip, peer.port);
                None
            }
        }
    }

    fn handshake(&mut self, info_hash: &[u8]) {
        self.send_handshake(info_hash);
        self.receive_handshake();
    }

    fn send_handshake(&mut self, info_hash: &[u8]) {
        let mut message = vec![];
        message.push(19);
        message.extend("BitTorrent protocol".as_bytes().iter().cloned());
        message.push(0);
        message.push(0);
        message.push(0);
        message.push(0);
        message.push(0);
        message.push(0);
        message.push(0);
        message.push(0);
        message.extend(info_hash.iter().cloned());
        message.extend("-TZ-0000-00000000001".as_bytes().iter().cloned());
        self.stream.write_all(&message).unwrap();
    }

    fn receive_handshake(&mut self) {
        let pstrlen = self.read_n(1);
        let pstr = self.read_n(pstrlen[0] as usize);
        let reserved = self.read_n(8);
        let info_hash = self.read_n(20);
        let peer_id = self.read_n(20);
    }

    fn read_n(&mut self, bytes_to_read: usize) -> Vec<u8> {
        let mut buf = vec![];
        let bytes_read = (&mut self.stream).take(bytes_to_read as u64).read_to_end(&mut buf);
        match bytes_read {
            Ok(n)  => assert_eq!(bytes_to_read as usize, n),
            Err(_) => panic!("Didn't read enough"),
        }
        buf
    }
}
<|endoftext|>


<commit_before>mod ui;

use crate::config::Config;
use crate::err::{self, Result};
use crate::file::{SaveDir, SaveFile};
use crate::track::{EntryState, SeriesTracker};
use crate::util;
use crate::CurrentWatchInfo;
use anime::remote::{RemoteService, SeriesInfo};
use anime::{SeasonInfoList, Series};
use chrono::{DateTime, Duration, Utc};
use clap::ArgMatches;
use snafu::{OptionExt, ResultExt};
use std::borrow::Cow;
use std::ops::Add;
use std::process;
use termion::event::Key;
use ui::{Event, Events, LogItem, UI};

pub fn run(args: &ArgMatches) -> Result<()> {
    let cstate = {
        let config = crate::get_config()?;
        let remote = crate::get_remote(args, true)?;

        CommonState {
            args,
            config,
            remote,
        }
    };

    let mut ui_state = {
        let watch_info = crate::get_watch_info(args)?;
        let series = SeriesState::new(&cstate, watch_info, true)?;
        let series_names = SaveDir::LocalData.get_subdirs()?;
        let selected_series = series_names
            .iter()
            .position(|s| *s == series.watch_info.name)
            .unwrap_or(0);

        UIState {
            series,
            series_names,
            selected_series,
            selection: Selection::Series,
        }
    };

    let mut ui = UI::init()?;
    let events = Events::new(Duration::seconds(1));

    loop {
        ui.draw(&ui_state)?;

        match events.next()? {
            Event::Input(key) => match key {
                // Exit
                Key::Char('q') => {
                    // Prevent ruining the user's terminal
                    ui.clear().ok();
                    break Ok(());
                }
                key => match ui_state.process_key(&cstate, &mut ui, key) {
                    Ok(_) => (),
                    Err(err) => {
                        ui.push_log_status(LogItem::failed("Processing key", err));
                    }
                },
            },
            Event::Tick => match ui_state.process_tick(&cstate, &mut ui) {
                Ok(_) => (),
                Err(err) => ui.push_log_status(LogItem::failed("Processing tick", err)),
            },
        }
    }
}

/// Items that are not tied to the UI and are commonly used together.
struct CommonState<'a> {
    args: &'a ArgMatches<'a>,
    config: Config,
    remote: Box<RemoteService>,
}

/// Current state of the UI.
pub struct UIState<'a> {
    series: SeriesState<'a>,
    series_names: Vec<String>,
    selected_series: usize,
    selection: Selection,
}

impl<'a> UIState<'a> {
    fn process_key<B>(&mut self, state: &'a CommonState, ui: &mut UI<B>, key: Key) -> Result<()>
    where
        B: tui::backend::Backend,
    {
        match key {
            // Sync list entry from / to remote
            Key::Char(ch @ 'r') | Key::Char(ch @ 's') => {
                let remote = state.remote.as_ref();

                let name = &self.series.watch_info.name;
                let season = &mut self.series.season;
                let entry = &mut season.tracker.state;

                if ch == 'r' {
                    ui.log_capture("Syncing entry from remote", || {
                        entry.force_sync_changes_from_remote(remote, name)
                    });
                } else if ch == 's' {
                    ui.log_capture("Syncing entry to remote", || {
                        entry.force_sync_changes_to_remote(remote, name)
                    });
                }

                season.update_value_cache(remote);
            }
            // Play next episode
            Key::Char('\n') => {
                self.series.set_last_watched(ui);

                ui.log_capture("Playing next episode", || {
                    self.series.season.play_next_episode_async(&state)
                });
            }
            // Switch between series and season selection
            Key::Left | Key::Right if self.is_idle() => {
                self.selection.set_opposite();
            }
            // Select series
            Key::Up | Key::Down if self.can_select_series() => {
                let index = UIState::next_arrow_key_value(key, self.selected_series);

                let new_name = match self.series_names.get(index) {
                    Some(new_name) => new_name,
                    None => return Ok(()),
                };

                let watch_info = CurrentWatchInfo::new(new_name, 0);

                self.series = SeriesState::new(state, watch_info, false)?;
                self.selected_series = index;
            }
            // Select season
            Key::Up | Key::Down if self.can_select_season() => {
                let remote = state.remote.as_ref();
                let new_season = UIState::next_arrow_key_value(key, self.series.watch_info.season);
                self.series.set_season(new_season, remote)?;
            }
            _ => (),
        }

        Ok(())
    }

    fn process_tick<B>(&mut self, state: &'a CommonState, ui: &mut UI<B>) -> Result<()>
    where
        B: tui::backend::Backend,
    {
        self.series.season.process_tick(state, ui)
    }

    fn next_arrow_key_value(key: Key, value: usize) -> usize {
        match key {
            Key::Up => value.saturating_sub(1),
            Key::Down => value + 1,
            _ => value,
        }
    }

    fn is_idle(&self) -> bool {
        self.series.season.watch_state == WatchState::Idle
    }

    fn can_select_season(&self) -> bool {
        self.selection == Selection::Season && self.is_idle()
    }

    fn can_select_series(&self) -> bool {
        self.selection == Selection::Series && self.is_idle()
    }
}

#[derive(PartialEq, Copy, Clone)]
pub enum Selection {
    Series,
    Season,
}

impl Selection {
    fn opposite(self) -> Selection {
        match self {
            Selection::Series => Selection::Season,
            Selection::Season => Selection::Series,
        }
    }

    fn set_opposite(&mut self) {
        *self = self.opposite();
    }
}

pub type ProgressTime = DateTime<Utc>;
pub type StartTime = DateTime<Utc>;

pub enum WatchState {
    Idle,
    Watching(StartTime, ProgressTime, process::Child),
}

impl PartialEq for WatchState {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (WatchState::Idle, WatchState::Idle) => true,
            (WatchState::Watching(_, _, _), WatchState::Watching(_, _, _)) => true,
            _ => false,
        }
    }
}

struct SeriesState<'a> {
    watch_info: CurrentWatchInfo,
    season: SeasonState<'a>,
    seasons: SeasonInfoList,
    num_seasons: usize,
    is_last_watched: bool,
}

impl<'a> SeriesState<'a> {
    fn new(
        state: &'a CommonState,
        watch_info: CurrentWatchInfo,
        is_last_watched: bool,
    ) -> Result<SeriesState<'a>> {
        let remote = state.remote.as_ref();
        let name = &watch_info.name;

        let episodes = crate::get_episodes(&state.args, name, &state.config)?;
        let seasons = crate::get_season_list(name, remote, &episodes)?;
        let num_seasons = seasons.len();
        let series = Series::from_season_list(&seasons, watch_info.season, episodes)?;
        let season = SeasonState::new(remote, name, series)?;

        Ok(SeriesState {
            watch_info,
            season,
            seasons,
            num_seasons,
            is_last_watched,
        })
    }

    /// Loads the season specified by `season_num` and points `season` to it.
    fn set_season<R>(&mut self, season_num: usize, remote: &'a R) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        if !self.seasons.has(season_num) {
            return Ok(());
        }

        let episodes = self.season.series.episodes.clone();
        let series = Series::from_season_list(&self.seasons, season_num, episodes)?;

        self.season = SeasonState::new(remote, &self.watch_info.name, series)?;
        self.watch_info.season = season_num;

        Ok(())
    }

    /// Sets the current series as the last watched one if it isn't already.
    fn set_last_watched<B>(&mut self, ui: &mut UI<B>)
    where
        B: tui::backend::Backend,
    {
        if self.is_last_watched {
            return;
        }

        ui.log_capture("Marking as the last watched series", || {
            self.watch_info.save(None)
        });

        self.is_last_watched = true;
    }
}

pub struct SeasonState<'a> {
    pub series: Series<'a>,
    pub tracker: SeriesTracker<'a>,
    pub value_cache: SeasonValueCache<'a>,
    pub watch_state: WatchState,
}

impl<'a> SeasonState<'a> {
    fn new<R, S>(remote: &'a R, name: S, series: Series<'a>) -> Result<SeasonState<'a>>
    where
        R: RemoteService + ?Sized,
        S: Into<String>,
    {
        let tracker = SeriesTracker::init(series.info.clone(), name)?;
        let value_cache = SeasonValueCache::new(remote, &tracker);

        Ok(SeasonState {
            series,
            tracker,
            value_cache,
            watch_state: WatchState::Idle,
        })
    }

    fn play_next_episode_async(&mut self, state: &CommonState) -> Result<()> {
        let remote = state.remote.as_ref();
        let config = &state.config;

        self.tracker.begin_watching(remote, config)?;
        let next_ep = self.tracker.state.watched_eps() + 1;

        let episode = self
            .series
            .get_episode(next_ep)
            .context(err::EpisodeNotFound { episode: next_ep })?;

        let start_time = Utc::now();

        let child = crate::process::open_with_default(episode)
            .context(err::FailedToPlayEpisode { episode: next_ep })?;

        let progress_time = {
            let secs_must_watch =
                (self.series.info.episode_length as f32 * config.episode.pcnt_must_watch) * 60.0;
            let time_must_watch = Duration::seconds(secs_must_watch as i64);

            start_time.add(time_must_watch)
        };

        self.watch_state = WatchState::Watching(start_time, progress_time, child);

        Ok(())
    }

    fn process_tick<B>(&mut self, state: &'a CommonState, ui: &mut UI<B>) -> Result<()>
    where
        B: tui::backend::Backend,
    {
        match &mut self.watch_state {
            WatchState::Idle => (),
            WatchState::Watching(start_time, _, child) => {
                let status = match child.try_wait().context(err::IO)? {
                    Some(status) => status,
                    None => return Ok(()),
                };

                if !status.success() {
                    ui.push_log_status("Player did not exit properly");
                    return Ok(());
                }

                let mins_watched = {
                    let watch_time = Utc::now() - *start_time;
                    watch_time.num_seconds() as f32 / 60.0
                };

                let remote = state.remote.as_ref();
                let config = &state.config;

                let mins_must_watch =
                    self.series.info.episode_length as f32 * config.episode.pcnt_must_watch;

                if mins_watched >= mins_must_watch {
                    ui.log_capture("Marking episode as completed", || {
                        self.tracker.episode_completed(remote, config)
                    });
                } else {
                    ui.push_log_status("Not marking episode as completed");
                }

                self.watch_state = WatchState::Idle;
                self.update_value_cache(remote);
            }
        }

        Ok(())
    }

    fn update_value_cache<R>(&mut self, remote: &'a R)
    where
        R: RemoteService + ?Sized,
    {
        self.value_cache.update(remote, &self.tracker);
    }
}

pub struct SeasonValueCache<'a> {
    pub progress: String,
    pub score: Cow<'a, str>,
    pub start_date: Cow<'a, str>,
    pub end_date: Cow<'a, str>,
    pub watch_time_left: String,
    // The following fields will not change
    pub watch_time: String,
    pub episode_length: String,
}

impl<'a> SeasonValueCache<'a> {
    pub fn new<R>(remote: &'a R, tracker: &SeriesTracker<'a>) -> SeasonValueCache<'a>
    where
        R: RemoteService + ?Sized,
    {
        let info = &tracker.info;
        let entry = &tracker.state;

        let watch_time = {
            let watch_time_mins = info.episodes * info.episode_length;
            util::hm_from_mins(watch_time_mins as f32)
        };

        let episode_length = format!("{}M", info.episode_length);

        SeasonValueCache {
            progress: SeasonValueCache::progress(info, entry),
            score: SeasonValueCache::score(remote, entry),
            start_date: SeasonValueCache::start_date(entry),
            end_date: SeasonValueCache::end_date(entry),
            watch_time_left: SeasonValueCache::watch_time_left(info, entry),
            watch_time,
            episode_length,
        }
    }

    pub fn update<R>(&mut self, remote: &'a R, tracker: &SeriesTracker<'a>)
    where
        R: RemoteService + ?Sized,
    {
        let info = &tracker.info;
        let entry = &tracker.state;

        self.progress = SeasonValueCache::progress(info, entry);
        self.score = SeasonValueCache::score(remote, entry);
        self.start_date = SeasonValueCache::start_date(entry);
        self.end_date = SeasonValueCache::end_date(entry);
        self.watch_time_left = SeasonValueCache::watch_time_left(info, entry);
    }

    fn progress(info: &SeriesInfo, entry: &EntryState) -> String {
        format!("{}|{}", entry.watched_eps(), info.episodes)
    }

    fn score<R>(remote: &'a R, entry: &EntryState) -> Cow<'a, str>
    where
        R: RemoteService + ?Sized,
    {
        match entry.score() {
            Some(score) => remote.score_to_str(score),
            None => "??".into(),
        }
    }

    fn start_date(entry: &EntryState) -> Cow<'a, str> {
        match entry.start_date() {
            Some(date) => format!("{}", date.format("%D")).into(),
            None => "??".into(),
        }
    }

    fn end_date(entry: &EntryState) -> Cow<'a, str> {
        match entry.end_date() {
            Some(date) => format!("{}", date.format("%D")).into(),
            None => "??".into(),
        }
    }

    fn watch_time_left(info: &SeriesInfo, entry: &EntryState) -> String {
        let time_left_mins = (info.episodes - entry.watched_eps()) * info.episode_length;
        util::hm_from_mins(time_left_mins as f32)
    }
}
<commit_msg>[anup] Add drop (d) and put on hold (h) keybindings for the TUI<commit_after>mod ui;

use crate::config::Config;
use crate::err::{self, Result};
use crate::file::{SaveDir, SaveFile};
use crate::track::{EntryState, SeriesTracker};
use crate::util;
use crate::CurrentWatchInfo;
use anime::remote::{RemoteService, SeriesInfo};
use anime::{SeasonInfoList, Series};
use chrono::{DateTime, Duration, Utc};
use clap::ArgMatches;
use snafu::{OptionExt, ResultExt};
use std::borrow::Cow;
use std::ops::Add;
use std::process;
use termion::event::Key;
use ui::{Event, Events, LogItem, UI};

pub fn run(args: &ArgMatches) -> Result<()> {
    let cstate = {
        let config = crate::get_config()?;
        let remote = crate::get_remote(args, true)?;

        CommonState {
            args,
            config,
            remote,
        }
    };

    let mut ui_state = {
        let watch_info = crate::get_watch_info(args)?;
        let series = SeriesState::new(&cstate, watch_info, true)?;
        let series_names = SaveDir::LocalData.get_subdirs()?;
        let selected_series = series_names
            .iter()
            .position(|s| *s == series.watch_info.name)
            .unwrap_or(0);

        UIState {
            series,
            series_names,
            selected_series,
            selection: Selection::Series,
        }
    };

    let mut ui = UI::init()?;
    let events = Events::new(Duration::seconds(1));

    loop {
        ui.draw(&ui_state)?;

        match events.next()? {
            Event::Input(key) => match key {
                // Exit
                Key::Char('q') => {
                    // Prevent ruining the user's terminal
                    ui.clear().ok();
                    break Ok(());
                }
                key => match ui_state.process_key(&cstate, &mut ui, key) {
                    Ok(_) => (),
                    Err(err) => {
                        ui.push_log_status(LogItem::failed("Processing key", err));
                    }
                },
            },
            Event::Tick => match ui_state.process_tick(&cstate, &mut ui) {
                Ok(_) => (),
                Err(err) => ui.push_log_status(LogItem::failed("Processing tick", err)),
            },
        }
    }
}

/// Items that are not tied to the UI and are commonly used together.
struct CommonState<'a> {
    args: &'a ArgMatches<'a>,
    config: Config,
    remote: Box<RemoteService>,
}

/// Current state of the UI.
pub struct UIState<'a> {
    series: SeriesState<'a>,
    series_names: Vec<String>,
    selected_series: usize,
    selection: Selection,
}

impl<'a> UIState<'a> {
    fn process_key<B>(&mut self, state: &'a CommonState, ui: &mut UI<B>, key: Key) -> Result<()>
    where
        B: tui::backend::Backend,
    {
        match key {
            // Sync list entry from / to remote
            Key::Char(ch @ 'r') | Key::Char(ch @ 's') => {
                let remote = state.remote.as_ref();
                let name = &self.series.watch_info.name;

                let season = &mut self.series.season;
                let entry = &mut season.tracker.state;

                if ch == 'r' {
                    ui.log_capture("Syncing entry from remote", || {
                        entry.force_sync_changes_from_remote(remote, name)
                    });
                } else if ch == 's' {
                    ui.log_capture("Syncing entry to remote", || {
                        entry.force_sync_changes_to_remote(remote, name)
                    });
                }

                season.update_value_cache(remote);
            }
            // Drop series / put on hold
            Key::Char(ch @ 'd') | Key::Char(ch @ 'h') => {
                let remote = state.remote.as_ref();
                let name = &self.series.watch_info.name;

                let season = &mut self.series.season;
                let entry = &mut season.tracker.state;

                if ch == 'd' {
                    entry.mark_as_dropped(&state.config);

                    ui.log_capture("Dropping series", || {
                        entry.force_sync_changes_to_remote(remote, name)
                    });
                } else if ch == 'h' {
                    entry.mark_as_on_hold();

                    ui.log_capture("Putting series on hold", || {
                        entry.force_sync_changes_to_remote(remote, name)
                    });
                }

                season.update_value_cache(remote);
            }
            // Play next episode
            Key::Char('\n') => {
                self.series.set_last_watched(ui);

                ui.log_capture("Playing next episode", || {
                    self.series.season.play_next_episode_async(&state)
                });
            }
            // Switch between series and season selection
            Key::Left | Key::Right if self.is_idle() => {
                self.selection.set_opposite();
            }
            // Select series
            Key::Up | Key::Down if self.can_select_series() => {
                let index = UIState::next_arrow_key_value(key, self.selected_series);

                let new_name = match self.series_names.get(index) {
                    Some(new_name) => new_name,
                    None => return Ok(()),
                };

                let watch_info = CurrentWatchInfo::new(new_name, 0);

                self.series = SeriesState::new(state, watch_info, false)?;
                self.selected_series = index;
            }
            // Select season
            Key::Up | Key::Down if self.can_select_season() => {
                let remote = state.remote.as_ref();
                let new_season = UIState::next_arrow_key_value(key, self.series.watch_info.season);
                self.series.set_season(new_season, remote)?;
            }
            _ => (),
        }

        Ok(())
    }

    fn process_tick<B>(&mut self, state: &'a CommonState, ui: &mut UI<B>) -> Result<()>
    where
        B: tui::backend::Backend,
    {
        self.series.season.process_tick(state, ui)
    }

    fn next_arrow_key_value(key: Key, value: usize) -> usize {
        match key {
            Key::Up => value.saturating_sub(1),
            Key::Down => value + 1,
            _ => value,
        }
    }

    fn is_idle(&self) -> bool {
        self.series.season.watch_state == WatchState::Idle
    }

    fn can_select_season(&self) -> bool {
        self.selection == Selection::Season && self.is_idle()
    }

    fn can_select_series(&self) -> bool {
        self.selection == Selection::Series && self.is_idle()
    }
}

#[derive(PartialEq, Copy, Clone)]
pub enum Selection {
    Series,
    Season,
}

impl Selection {
    fn opposite(self) -> Selection {
        match self {
            Selection::Series => Selection::Season,
            Selection::Season => Selection::Series,
        }
    }

    fn set_opposite(&mut self) {
        *self = self.opposite();
    }
}

pub type ProgressTime = DateTime<Utc>;
pub type StartTime = DateTime<Utc>;

pub enum WatchState {
    Idle,
    Watching(StartTime, ProgressTime, process::Child),
}

impl PartialEq for WatchState {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (WatchState::Idle, WatchState::Idle) => true,
            (WatchState::Watching(_, _, _), WatchState::Watching(_, _, _)) => true,
            _ => false,
        }
    }
}

struct SeriesState<'a> {
    watch_info: CurrentWatchInfo,
    season: SeasonState<'a>,
    seasons: SeasonInfoList,
    num_seasons: usize,
    is_last_watched: bool,
}

impl<'a> SeriesState<'a> {
    fn new(
        state: &'a CommonState,
        watch_info: CurrentWatchInfo,
        is_last_watched: bool,
    ) -> Result<SeriesState<'a>> {
        let remote = state.remote.as_ref();
        let name = &watch_info.name;

        let episodes = crate::get_episodes(&state.args, name, &state.config)?;
        let seasons = crate::get_season_list(name, remote, &episodes)?;
        let num_seasons = seasons.len();
        let series = Series::from_season_list(&seasons, watch_info.season, episodes)?;
        let season = SeasonState::new(remote, name, series)?;

        Ok(SeriesState {
            watch_info,
            season,
            seasons,
            num_seasons,
            is_last_watched,
        })
    }

    /// Loads the season specified by `season_num` and points `season` to it.
    fn set_season<R>(&mut self, season_num: usize, remote: &'a R) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        if !self.seasons.has(season_num) {
            return Ok(());
        }

        let episodes = self.season.series.episodes.clone();
        let series = Series::from_season_list(&self.seasons, season_num, episodes)?;

        self.season = SeasonState::new(remote, &self.watch_info.name, series)?;
        self.watch_info.season = season_num;

        Ok(())
    }

    /// Sets the current series as the last watched one if it isn't already.
    fn set_last_watched<B>(&mut self, ui: &mut UI<B>)
    where
        B: tui::backend::Backend,
    {
        if self.is_last_watched {
            return;
        }

        ui.log_capture("Marking as the last watched series", || {
            self.watch_info.save(None)
        });

        self.is_last_watched = true;
    }
}

pub struct SeasonState<'a> {
    pub series: Series<'a>,
    pub tracker: SeriesTracker<'a>,
    pub value_cache: SeasonValueCache<'a>,
    pub watch_state: WatchState,
}

impl<'a> SeasonState<'a> {
    fn new<R, S>(remote: &'a R, name: S, series: Series<'a>) -> Result<SeasonState<'a>>
    where
        R: RemoteService + ?Sized,
        S: Into<String>,
    {
        let tracker = SeriesTracker::init(series.info.clone(), name)?;
        let value_cache = SeasonValueCache::new(remote, &tracker);

        Ok(SeasonState {
            series,
            tracker,
            value_cache,
            watch_state: WatchState::Idle,
        })
    }

    fn play_next_episode_async(&mut self, state: &CommonState) -> Result<()> {
        let remote = state.remote.as_ref();
        let config = &state.config;

        self.tracker.begin_watching(remote, config)?;
        let next_ep = self.tracker.state.watched_eps() + 1;

        let episode = self
            .series
            .get_episode(next_ep)
            .context(err::EpisodeNotFound { episode: next_ep })?;

        let start_time = Utc::now();

        let child = crate::process::open_with_default(episode)
            .context(err::FailedToPlayEpisode { episode: next_ep })?;

        let progress_time = {
            let secs_must_watch =
                (self.series.info.episode_length as f32 * config.episode.pcnt_must_watch) * 60.0;
            let time_must_watch = Duration::seconds(secs_must_watch as i64);

            start_time.add(time_must_watch)
        };

        self.watch_state = WatchState::Watching(start_time, progress_time, child);

        Ok(())
    }

    fn process_tick<B>(&mut self, state: &'a CommonState, ui: &mut UI<B>) -> Result<()>
    where
        B: tui::backend::Backend,
    {
        match &mut self.watch_state {
            WatchState::Idle => (),
            WatchState::Watching(start_time, _, child) => {
                let status = match child.try_wait().context(err::IO)? {
                    Some(status) => status,
                    None => return Ok(()),
                };

                if !status.success() {
                    ui.push_log_status("Player did not exit properly");
                    return Ok(());
                }

                let mins_watched = {
                    let watch_time = Utc::now() - *start_time;
                    watch_time.num_seconds() as f32 / 60.0
                };

                let remote = state.remote.as_ref();
                let config = &state.config;

                let mins_must_watch =
                    self.series.info.episode_length as f32 * config.episode.pcnt_must_watch;

                if mins_watched >= mins_must_watch {
                    ui.log_capture("Marking episode as completed", || {
                        self.tracker.episode_completed(remote, config)
                    });
                } else {
                    ui.push_log_status("Not marking episode as completed");
                }

                self.watch_state = WatchState::Idle;
                self.update_value_cache(remote);
            }
        }

        Ok(())
    }

    fn update_value_cache<R>(&mut self, remote: &'a R)
    where
        R: RemoteService + ?Sized,
    {
        self.value_cache.update(remote, &self.tracker);
    }
}

pub struct SeasonValueCache<'a> {
    pub progress: String,
    pub score: Cow<'a, str>,
    pub start_date: Cow<'a, str>,
    pub end_date: Cow<'a, str>,
    pub watch_time_left: String,
    // The following fields will not change
    pub watch_time: String,
    pub episode_length: String,
}

impl<'a> SeasonValueCache<'a> {
    pub fn new<R>(remote: &'a R, tracker: &SeriesTracker<'a>) -> SeasonValueCache<'a>
    where
        R: RemoteService + ?Sized,
    {
        let info = &tracker.info;
        let entry = &tracker.state;

        let watch_time = {
            let watch_time_mins = info.episodes * info.episode_length;
            util::hm_from_mins(watch_time_mins as f32)
        };

        let episode_length = format!("{}M", info.episode_length);

        SeasonValueCache {
            progress: SeasonValueCache::progress(info, entry),
            score: SeasonValueCache::score(remote, entry),
            start_date: SeasonValueCache::start_date(entry),
            end_date: SeasonValueCache::end_date(entry),
            watch_time_left: SeasonValueCache::watch_time_left(info, entry),
            watch_time,
            episode_length,
        }
    }

    pub fn update<R>(&mut self, remote: &'a R, tracker: &SeriesTracker<'a>)
    where
        R: RemoteService + ?Sized,
    {
        let info = &tracker.info;
        let entry = &tracker.state;

        self.progress = SeasonValueCache::progress(info, entry);
        self.score = SeasonValueCache::score(remote, entry);
        self.start_date = SeasonValueCache::start_date(entry);
        self.end_date = SeasonValueCache::end_date(entry);
        self.watch_time_left = SeasonValueCache::watch_time_left(info, entry);
    }

    fn progress(info: &SeriesInfo, entry: &EntryState) -> String {
        format!("{}|{}", entry.watched_eps(), info.episodes)
    }

    fn score<R>(remote: &'a R, entry: &EntryState) -> Cow<'a, str>
    where
        R: RemoteService + ?Sized,
    {
        match entry.score() {
            Some(score) => remote.score_to_str(score),
            None => "??".into(),
        }
    }

    fn start_date(entry: &EntryState) -> Cow<'a, str> {
        match entry.start_date() {
            Some(date) => format!("{}", date.format("%D")).into(),
            None => "??".into(),
        }
    }

    fn end_date(entry: &EntryState) -> Cow<'a, str> {
        match entry.end_date() {
            Some(date) => format!("{}", date.format("%D")).into(),
            None => "??".into(),
        }
    }

    fn watch_time_left(info: &SeriesInfo, entry: &EntryState) -> String {
        let time_left_mins = (info.episodes - entry.watched_eps()) * info.episode_length;
        util::hm_from_mins(time_left_mins as f32)
    }
}
<|endoftext|>