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

/// # Example
/// ```
/// use std::f32::consts::FRAC_2_PI;
/// let mut a = quat::new_identity::<f32>();
/// let mut b = quat::new_identity::<f32>();
///
/// quat::set_axis_angle(&mut a, &[0_f32, 0_f32, 1_f32], &FRAC_2_PI);
/// quat::set_axis_angle(&mut b, &[0_f32, 0_f32, 1_f32], &-FRAC_2_PI);
///
/// let mut q = quat::new_identity::<f32>();
/// quat::mul(&mut q, &a, &b);
/// assert_eq!(q, [0_f32, 0_f32, 0_f32, 1_f32]);
///
/// let mut axis = [0_f32; 3];
/// let angle = quat::axis_angle(&mut q, &mut axis);
///
/// assert_eq!(angle, 0_f32);
/// assert_eq!(axis, [0_f32, 0_f32, 1_f32]);
/// ```
#[inline]
pub fn mul<'out, T>(out: &'out mut [T; 4], a: &[T; 4], b: &[T; 4]) -> &'out mut [T; 4]
where
    T: Add<T, Output = T> + Sub<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
    out[0] = &a[0] * &b[3] + &a[3] * &b[0] + &a[1] * &b[2] - &a[2] * &b[1];
    out[1] = &a[1] * &b[3] + &a[3] * &b[1] + &a[2] * &b[0] - &a[0] * &b[2];
    out[2] = &a[2] * &b[3] + &a[3] * &b[2] + &a[0] * &b[1] - &a[1] * &b[0];
    out[3] = &a[3] * &b[3] - &a[0] * &b[0] - &a[1] * &b[1] - &a[2] * &b[2];
    out
}
/// rmul_mut(out, a) does out = a * out
/// # Example
/// ```
/// let mut q = quat::new_identity::<f32>();
/// quat::rmul_mut(&mut q, &quat::new_identity::<f32>());
/// assert_eq!(q, [0_f32, 0_f32, 0_f32, 1_f32]);
/// ```
#[inline]
pub fn rmul_mut<'out, T>(out: &'out mut [T; 4], a: &[T; 4]) -> &'out mut [T; 4]
where
    T: Clone + Add<T, Output = T> + Sub<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
    let tmp = out.clone();
    mul(out, a, &tmp)
}
/// lmul_mut(out, a) does out = out * a
/// # Example
/// ```
/// let mut q = quat::new_identity::<f32>();
/// quat::lmul_mut(&mut q, &quat::new_identity::<f32>());
/// assert_eq!(q, [0_f32, 0_f32, 0_f32, 1_f32]);
/// ```
#[inline]
pub fn lmul_mut<'out, T>(out: &'out mut [T; 4], a: &[T; 4]) -> &'out mut [T; 4]
where
    T: Clone + Add<T, Output = T> + Sub<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
    let tmp = out.clone();
    mul(out, &tmp, a)
}
/// # Example
/// ```
/// use std::f32::consts::FRAC_2_PI;
/// let mut a = quat::new_identity::<f32>();
/// let mut b = quat::new_identity::<f32>();
///
/// quat::set_axis_angle(&mut a, &[0_f32, 0_f32, 1_f32], &FRAC_2_PI);
/// quat::set_axis_angle(&mut b, &[0_f32, 0_f32, 1_f32], &FRAC_2_PI);
///
/// let mut q = quat::new_identity::<f32>();
/// quat::div(&mut q, &a, &b);
/// assert_eq!(q, [0_f32, 0_f32, 0_f32, 1_f32]);
///
/// let mut axis = [0_f32; 3];
/// let angle = quat::axis_angle(&mut q, &mut axis);
///
/// assert_eq!(angle, 0_f32);
/// assert_eq!(axis, [0_f32, 0_f32, 1_f32]);
/// ```
#[inline]
pub fn div<'out, T>(out: &'out mut [T; 4], a: &[T; 4], b: &[T; 4]) -> &'out mut [T; 4]
where
    T: Add<T, Output = T> + Sub<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T> + Neg<Output = T>,
{
    out[0] = &a[0] * &b[3] + &a[3] * &-&b[0] + &a[1] * &-&b[2] - &a[2] * &-&b[1];
    out[1] = &a[1] * &b[3] + &a[3] * &-&b[1] + &a[2] * &-&b[0] - &a[0] * &-&b[2];
    out[2] = &a[2] * &b[3] + &a[3] * &-&b[2] + &a[0] * &-&b[1] - &a[1] * &-&b[0];
    out[3] = &a[3] * &b[3] - &a[0] * &-&b[0] - &a[1] * &-&b[1] - &a[2] * &-&b[2];
    out
}
/// rdiv_mut(out, a) does out = a / out
/// # Example
/// ```
/// let mut q = quat::new_identity::<f32>();
/// quat::rdiv_mut(&mut q, &quat::new_identity::<f32>());
/// assert_eq!(q, [0_f32, 0_f32, 0_f32, 1_f32]);
/// ```
#[inline]
pub fn rdiv_mut<'out, T>(out: &'out mut [T; 4], a: &[T; 4]) -> &'out mut [T; 4]
where
    T: Clone + Add<T, Output = T> + Sub<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T> + Neg<Output = T>,
{
    let tmp = out.clone();
    div(out, a, &tmp)
}
/// ldiv_mut(out, a) does out = out / a
/// # Example
/// ```
/// let mut q = quat::new_identity::<f32>();
/// quat::ldiv_mut(&mut q, &quat::new_identity::<f32>());
/// assert_eq!(q, [0_f32, 0_f32, 0_f32, 1_f32]);
/// ```
#[inline]
pub fn ldiv_mut<'out, T>(out: &'out mut [T; 4], a: &[T; 4]) -> &'out mut [T; 4]
where
    T: Clone + Add<T, Output = T> + Sub<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T> + Neg<Output = T>,
{
    let tmp = out.clone();
    div(out, &tmp, a)
}