Documentation
use core::ops::{Add, Mul, Sub};

use num_traits::{One, Zero};

#[inline]
pub fn set<T>(
    out: &mut [T; 9],
    m00: T,
    m01: T,
    m02: T,
    m10: T,
    m11: T,
    m12: T,
    m20: T,
    m21: T,
    m22: T,
) -> &mut [T; 9] {
    out[0] = m00;
    out[3] = m01;
    out[6] = m02;
    out[1] = m10;
    out[4] = m11;
    out[7] = m12;
    out[2] = m20;
    out[5] = m21;
    out[8] = m22;
    out
}

#[inline(always)]
pub fn set_identity<T>(out: &mut [T; 9]) -> &mut [T; 9]
where
    T: One + Zero,
{
    set(
        out,
        T::one(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::one(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::one(),
    )
}

#[inline(always)]
pub fn set_zero<T>(out: &mut [T; 9]) -> &mut [T; 9]
where
    T: Zero,
{
    set(
        out,
        T::zero(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::zero(),
    )
}

#[inline(always)]
pub fn set_one<T>(out: &mut [T; 9]) -> &mut [T; 9]
where
    T: One,
{
    set(
        out,
        T::one(),
        T::one(),
        T::one(),
        T::one(),
        T::one(),
        T::one(),
        T::one(),
        T::one(),
        T::one(),
    )
}

#[inline]
pub fn set_mat2<'out, T>(out: &'out mut [T; 9], m: &[T; 4]) -> &'out mut [T; 9]
where
    T: One + Zero + Clone,
{
    set(
        out,
        m[0].clone(),
        m[2].clone(),
        T::zero(),
        m[1].clone(),
        m[3].clone(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::one(),
    )
}

#[inline]
pub fn set_mat32<'out, T>(out: &'out mut [T; 9], m: &[T; 6]) -> &'out mut [T; 9]
where
    T: One + Zero + Clone,
{
    set(
        out,
        m[0].clone(),
        m[2].clone(),
        T::zero(),
        m[1].clone(),
        m[3].clone(),
        T::zero(),
        T::zero(),
        T::zero(),
        T::one(),
    )
}

#[inline]
pub fn set_mat4<'out, T>(out: &'out mut [T; 9], m: &[T; 16]) -> &'out mut [T; 9]
where
    T: One + Zero + Clone,
{
    set(
        out,
        m[0].clone(),
        m[4].clone(),
        m[8].clone(),
        m[1].clone(),
        m[5].clone(),
        m[9].clone(),
        m[2].clone(),
        m[6].clone(),
        m[10].clone(),
    )
}

/// # Example
/// ```
/// let mut m = mat3::new_identity::<f32>();
/// mat3::set_quat(&mut m, &[0_f32, 0_f32, 0_f32, 1_f32]);
/// assert_eq!(m, mat3::new_identity::<f32>());
/// ```
#[inline]
pub fn set_quat<'out, T>(out: &'out mut [T; 9], q: &[T; 4]) -> &'out mut [T; 9]
where
    T: One,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T> + Add<&'b T, Output = T> + Sub<&'b T, Output = T>,
{
    let x = &q[0];
    let y = &q[1];
    let z = &q[2];
    let w = &q[3];
    let x2 = x + x;
    let y2 = y + y;
    let z2 = z + z;
    let xx = x * &x2;
    let xy = x * &y2;
    let xz = x * &z2;
    let yy = y * &y2;
    let yz = y * &z2;
    let zz = z * &z2;
    let wx = w * &x2;
    let wy = w * &y2;
    let wz = w * &z2;

    out[0] = &T::one() - &(&yy + &zz);
    out[1] = &xy + &wz;
    out[2] = &xz - &wy;

    out[3] = &xy - &wz;
    out[4] = &T::one() - &(&xx + &zz);
    out[5] = &yz + &wx;

    out[6] = &xz + &wy;
    out[7] = &yz - &wx;
    out[8] = &T::one() - &(&xx + &yy);
    out
}