//! # Mat3
//!
//! A 3x3 column-major matrix.
//!
//! # Conventions
//!
//! - Column-major
//! - Stored as 3 columns `col0`..`col2`, each a [`Vec3`]
//!
//! # Examples
//!
//! ```rust
//! # use roofy::{Mat3, Vec3};
//!
//! let m: Mat3 = Mat3::IDENTITY;
//! let scaled: Mat3 = m * Mat3::from_diagonal(Vec3::splat(2.0));
//!
//! assert_eq!(scaled.col0.x, 2.0);
//! assert_eq!(scaled.col1.y, 2.0);
//! assert_eq!(scaled.col2.z, 2.0);
//! ```

use std::{
    fmt::Display,
    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};

use crate::{Affine2, Mat2, Mat4, Quat, Vec2, Vec3};

/// A 3x3 column-major matrix.
///
/// Stored as 3 columns `col0`, `col1` and `col2`, each a [`Vec3`]
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub struct Mat3 {
    /// Column 0 of the matrix.
    pub col0: Vec3,
    /// Column 1 of the matrix.
    pub col1: Vec3,
    /// Column 2 of the matrix.
    pub col2: Vec3,
}

impl Mat3 {
    /// Threshold for treating a value as zero.
    pub const EPSILON: f32 = 1e-6;

    /// A 3x3 matrix with all components `NaN`.
    pub const NAN: Self = Self::from_cols(Vec3::NAN, Vec3::NAN, Vec3::NAN);

    /// A 3x3 matrix with all components `0.0`.
    pub const ZERO: Self = Self::from_cols(Vec3::ZERO, Vec3::ZERO, Vec3::ZERO);

    /// A 3x3 matrix, where all diagonal components are `1.0` and all others are `0.0`.
    pub const IDENTITY: Self = Self::from_cols(Vec3::X, Vec3::Y, Vec3::Z);

    /// Creates a `Mat3` from 9 `f32`, in column-major order.
    ///
    /// # Convention
    /// Parameters are named `mCR` where `C` is the column index and `R` is the row index.
    #[allow(clippy::too_many_arguments)]
    #[inline(always)]
    #[must_use]
    pub const fn new(
        m00: f32,
        m01: f32,
        m02: f32,
        m10: f32,
        m11: f32,
        m12: f32,
        m20: f32,
        m21: f32,
        m22: f32,
    ) -> Self {
        Self::from_cols(
            Vec3::new(m00, m01, m02),
            Vec3::new(m10, m11, m12),
            Vec3::new(m20, m21, m22),
        )
    }

    /// Creates a `Mat3` from 3 column `Vec3`.
    #[inline(always)]
    #[must_use]
    pub const fn from_cols(col0: Vec3, col1: Vec3, col2: Vec3) -> Self {
        Self { col0, col1, col2 }
    }

    /// Creates a `Mat3` with diagonal set to `v` and all other components `0.0`.
    #[inline]
    #[must_use]
    pub const fn from_diagonal(v: Vec3) -> Self {
        Self::from_cols(
            Vec3::new(v.x, 0.0, 0.0),
            Vec3::new(0.0, v.y, 0.0),
            Vec3::new(0.0, 0.0, v.z),
        )
    }

    /// Creates a `Mat3` from a `[f32; 9]`, in column-major order:
    /// `[col0.x, col0.y, col0.z, col1.x, ..., col2.z]`.
    #[inline]
    #[must_use]
    pub const fn from_array(a: [f32; 9]) -> Self {
        Self::new(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
    }

    /// Returns a copy of the components as `[col0, col1, col2]`,
    /// with each column as `[x, y, z]`, in column-major order.
    #[inline]
    #[must_use]
    pub const fn to_array(self) -> [f32; 9] {
        [
            self.col0.x,
            self.col0.y,
            self.col0.z,
            self.col1.x,
            self.col1.y,
            self.col1.z,
            self.col2.x,
            self.col2.y,
            self.col2.z,
        ]
    }

    /// Creates a `Mat3` from first 9 values of `slice`, in column-major order.
    ///
    /// # Panics
    /// Panics if `slice` is less than 9 elements long.
    #[inline]
    #[must_use]
    pub const fn from_slice(slice: &[f32]) -> Self {
        Self::new(
            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
            slice[8],
        )
    }

    /// Writes the columns of `self` to the first 9 elements of `slice`.
    ///
    /// # Panics
    /// Panics if `slice` is less than 9 elements long.
    #[inline]
    pub const fn write_to_slice(self, slice: &mut [f32]) {
        slice[0] = self.col0.x;
        slice[1] = self.col0.y;
        slice[2] = self.col0.z;
        slice[3] = self.col1.x;
        slice[4] = self.col1.y;
        slice[5] = self.col1.z;
        slice[6] = self.col2.x;
        slice[7] = self.col2.y;
        slice[8] = self.col2.z;
    }

    /// Creates a `Mat3` from a `Mat2`, setting `col2` and `row2` to identity.
    #[inline]
    #[must_use]
    pub const fn from_mat2(m: Mat2) -> Self {
        Self::from_cols(m.col0.to_vec3(), m.col1.to_vec3(), Vec3::Z)
    }

    /// Creates a `Mat3` from a `Mat4`, discarding `col3` and `row3`.
    #[inline]
    #[must_use]
    pub const fn from_mat4(m: Mat4) -> Self {
        Self::from_cols(m.col0.to_vec3(), m.col1.to_vec3(), m.col2.to_vec3())
    }

    /// Creates a `Mat3` that scales by `x` and `y` components of `v`,
    /// with `col2` and `row2` set to identity.
    ///
    /// # Convention
    /// Treats `Mat3` as a 2D homogeneous transform
    #[inline]
    #[must_use]
    pub const fn from_scale_2d(v: Vec2) -> Self {
        Self::from_cols(Vec3::new(v.x, 0.0, 0.0), Vec3::new(0.0, v.y, 0.0), Vec3::Z)
    }

    /// Creates a `Mat3` that rotates around the X axis by `angle` in radians.
    #[inline]
    #[must_use]
    pub fn from_rotation_x(angle: f32) -> Self {
        let (s, c): (f32, f32) = angle.sin_cos();

        Self::from_cols(Vec3::X, Vec3::new(0.0, c, s), Vec3::new(0.0, -s, c))
    }

    /// Creates a `Mat3` that rotates around the X axis by `angle` in degrees.
    #[inline]
    #[must_use]
    pub fn from_rotation_x_degrees(angle: f32) -> Self {
        Self::from_rotation_x(angle.to_radians())
    }

    /// Creates a `Mat3` that rotates around the Y axis by `angle` in radians.
    #[inline]
    #[must_use]
    pub fn from_rotation_y(angle: f32) -> Self {
        let (s, c): (f32, f32) = angle.sin_cos();

        Self::from_cols(Vec3::new(c, 0.0, -s), Vec3::Y, Vec3::new(s, 0.0, c))
    }

    /// Creates a `Mat3` that rotates around the Y axis by `angle` in degrees.
    #[inline]
    #[must_use]
    pub fn from_rotation_y_degrees(angle: f32) -> Self {
        Self::from_rotation_y(angle.to_radians())
    }

    /// Creates a `Mat3` that rotates around the Z axis by `angle` in radians.
    #[inline]
    #[must_use]
    pub fn from_rotation_z(angle: f32) -> Self {
        let (s, c): (f32, f32) = angle.sin_cos();

        Self::from_cols(Vec3::new(c, s, 0.0), Vec3::new(-s, c, 0.0), Vec3::Z)
    }

    /// Creates a `Mat3` that rotates around the Z axis by `angle` in degrees.
    #[inline]
    #[must_use]
    pub fn from_rotation_z_degrees(angle: f32) -> Self {
        Self::from_rotation_z(angle.to_radians())
    }

    /// Creates a `Mat3` from a `rotation` as euler angles in a `Vec3` in radians and a `scale`.
    ///
    /// Applied in order: scale -> rotation.
    #[inline]
    #[must_use]
    pub fn from_rs_euler(rotation: Vec3, scale: Vec3) -> Self {
        let r: Self = Self::from_rotation_x(rotation.x)
            * Self::from_rotation_y(rotation.y)
            * Self::from_rotation_z(rotation.z);
        let s: Self = Self::from_diagonal(scale);

        r * s
    }

    /// Creates a `Mat3` from a `rotation` as euler angles in a `Vec3` in degrees and a `scale`.
    ///
    /// Applied in order: scale -> rotation.
    #[inline]
    #[must_use]
    pub fn from_rs_euler_degrees(rotation: Vec3, scale: Vec3) -> Self {
        let r: Self = Self::from_rotation_x_degrees(rotation.x)
            * Self::from_rotation_y_degrees(rotation.y)
            * Self::from_rotation_z_degrees(rotation.z);
        let s: Self = Self::from_diagonal(scale);

        r * s
    }

    /// Creates a `Mat3` from a `rotation` as a `Quat` and a `scale`.
    ///
    /// Applied in order: scale -> rotate.
    #[inline]
    #[must_use]
    pub fn from_rs(rotation: Quat, scale: Vec3) -> Self {
        Self::from_quat(rotation) * Self::from_diagonal(scale)
    }

    /// Creates a `Mat3` that rotates by `Quat`.
    ///
    /// # Preconditions
    /// Expects `q` to be normalized.
    #[inline]
    #[must_use]
    pub const fn from_quat(q: Quat) -> Self {
        let x2: f32 = q.x * q.x;
        let y2: f32 = q.y * q.y;
        let z2: f32 = q.z * q.z;
        let xy: f32 = q.x * q.y;
        let xz: f32 = q.x * q.z;
        let yz: f32 = q.y * q.z;
        let wx: f32 = q.w * q.x;
        let wy: f32 = q.w * q.y;
        let wz: f32 = q.w * q.z;

        Self::from_cols(
            Vec3::new(1.0 - 2.0 * (y2 + z2), 2.0 * (xy + wz), 2.0 * (xz - wy)),
            Vec3::new(2.0 * (xy - wz), 1.0 - 2.0 * (x2 + z2), 2.0 * (yz + wx)),
            Vec3::new(2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (x2 + y2)),
        )
    }

    /// Creates a `Mat3` that rotates around `axis` by `angle` in radians.
    ///
    /// # Preconditions
    /// Expects `axis` to be normalized.
    #[inline]
    #[must_use]
    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
        Self::from_quat(Quat::from_axis_angle(axis, angle))
    }

    /// Creates a `Mat3` that rotates around `axis` by `angle` in degrees.
    ///
    /// # Preconditions
    /// Expects `axis` to be normalized.
    #[inline]
    #[must_use]
    pub fn from_axis_angle_degrees(axis: Vec3, angle: f32) -> Self {
        Self::from_quat(Quat::from_axis_angle_degrees(axis, angle))
    }

    /// Returns the component-wise sum of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn add(self, rhs: Self) -> Self {
        Self::from_cols(
            self.col0.add(rhs.col0),
            self.col1.add(rhs.col1),
            self.col2.add(rhs.col2),
        )
    }

    /// Sets self to the component-wise sum of `self` and `rhs`.
    #[inline]
    pub const fn add_assign(&mut self, rhs: Self) {
        self.col0.add_assign(rhs.col0);
        self.col1.add_assign(rhs.col1);
        self.col2.add_assign(rhs.col2);
    }

    /// Returns the component-wise difference of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn sub(self, rhs: Self) -> Self {
        Self::from_cols(
            self.col0.sub(rhs.col0),
            self.col1.sub(rhs.col1),
            self.col2.sub(rhs.col2),
        )
    }

    /// Sets self to the component-wise difference of `self` and `rhs`.
    #[inline]
    pub const fn sub_assign(&mut self, rhs: Self) {
        self.col0.sub_assign(rhs.col0);
        self.col1.sub_assign(rhs.col1);
        self.col2.sub_assign(rhs.col2);
    }

    /// Returns the matrix product of `self` and `rhs`.
    #[inline]
    #[must_use]
    pub const fn mul(self, rhs: Self) -> Self {
        Self::from_cols(
            self.mul_vec3(rhs.col0),
            self.mul_vec3(rhs.col1),
            self.mul_vec3(rhs.col2),
        )
    }

    /// Sets `self` to the matrix product of `self` and `rhs`.
    #[inline]
    pub const fn mul_assign(&mut self, rhs: Self) {
        *self = self.mul(rhs);
    }

    /// Returns `rhs` transformed by `self`.
    ///
    /// Equivalent to [`transform`](Self::transform()).
    #[inline]
    #[must_use]
    pub const fn mul_vec3(self, rhs: Vec3) -> Vec3 {
        self.transform(rhs)
    }

    /// Returns `self` with each component multiplied by `rhs`.
    #[inline]
    #[must_use]
    pub const fn mul_scalar(self, rhs: f32) -> Self {
        Self::from_cols(
            self.col0.mul_scalar(rhs),
            self.col1.mul_scalar(rhs),
            self.col2.mul_scalar(rhs),
        )
    }

    /// Sets `self` to `self` with each component multiplied by `rhs`.
    #[inline]
    pub const fn mul_assign_scalar(&mut self, rhs: f32) {
        *self = self.mul_scalar(rhs);
    }

    /// Returns `self` with each component divided by `rhs`.
    #[inline]
    #[must_use]
    pub const fn div_scalar(self, rhs: f32) -> Self {
        Self::from_cols(
            self.col0.div_scalar(rhs),
            self.col1.div_scalar(rhs),
            self.col2.div_scalar(rhs),
        )
    }

    /// Sets `self` to `self` with each component divided by `rhs`.
    #[inline]
    pub const fn div_assign_scalar(&mut self, rhs: f32) {
        *self = self.div_scalar(rhs);
    }

    /// Returns `self` with negated components.
    #[inline]
    #[must_use]
    pub const fn neg(self) -> Self {
        Self::from_cols(self.col0.neg(), self.col1.neg(), self.col2.neg())
    }

    /// Returns a reference to the components as `[col0, col1, col2]`,
    /// with each column as `[x, y, z]`.
    ///
    /// # Safety
    /// Relies on `Mat3` being `#[repr(C)]`
    ///
    /// # Convention
    /// Array is in column-major order.
    #[inline]
    #[must_use]
    pub const fn as_ref(&self) -> &[f32; 9] {
        unsafe { &*(self as *const Mat3 as *const [f32; 9]) }
    }

    /// Returns a mutable reference to the components as `[col0, col1, col2]`,
    /// with each column as `[x, y, z]`.
    ///
    /// # Safety
    /// Relies on `Mat3` being `#[repr(C)]`
    ///
    /// # Convention
    /// Array is in column-major order.
    #[inline]
    #[must_use]
    pub const fn as_mut(&mut self) -> &mut [f32; 9] {
        unsafe { &mut *(self as *mut Mat3 as *mut [f32; 9]) }
    }

    /// Returns all columns of `self`.
    #[inline]
    #[must_use]
    pub const fn cols(self) -> [Vec3; 3] {
        [self.col0, self.col1, self.col2]
    }

    /// Returns column of `self` at `index`.
    ///
    /// `0` maps to `col0`, `1` maps to `col1`, `2` maps to `col2`.
    ///
    /// # Panics
    /// Panics if `index` is greater than `2`.
    #[inline]
    pub const fn col(self, index: usize) -> Vec3 {
        match index {
            0 => self.col0,
            1 => self.col1,
            2 => self.col2,
            _ => panic!("index out of bounds"),
        }
    }

    /// Returns row 0 of `self`.
    #[inline]
    #[must_use]
    pub const fn row0(self) -> Vec3 {
        Vec3::new(self.col0.x, self.col1.x, self.col2.x)
    }

    /// Returns row 1 of `self`.
    #[inline]
    #[must_use]
    pub const fn row1(self) -> Vec3 {
        Vec3::new(self.col0.y, self.col1.y, self.col2.y)
    }

    /// Returns row 2 of `self`.
    #[inline]
    #[must_use]
    pub const fn row2(self) -> Vec3 {
        Vec3::new(self.col0.z, self.col1.z, self.col2.z)
    }

    /// Returns all rows of `self`.
    #[inline]
    #[must_use]
    pub const fn rows(self) -> [Vec3; 3] {
        [self.row0(), self.row1(), self.row2()]
    }

    /// Returns row of `self` at `index`.
    ///
    /// `0` maps to `row0`, `1` maps to `row1`, `2` maps to `row2`.
    ///
    /// # Panics
    /// Panics if `index` is greater than `2`.
    #[inline]
    #[must_use]
    pub const fn row(self, index: usize) -> Vec3 {
        match index {
            0 => self.row0(),
            1 => self.row1(),
            2 => self.row2(),
            _ => panic!("index out of bounds"),
        }
    }

    /// Returns the transpose of `self`.
    #[inline]
    #[must_use]
    pub const fn transpose(self) -> Self {
        Self::from_cols(self.row0(), self.row1(), self.row2())
    }

    /// Returns the diagonal of `self`.
    #[inline]
    #[must_use]
    pub const fn diagonal(self) -> Vec3 {
        Vec3::new(self.col0.x, self.col1.y, self.col2.z)
    }

    /// Returns the determinant of `self`.
    #[inline]
    #[must_use]
    pub const fn determinant(self) -> f32 {
        self.col2.dot(self.col0.cross(self.col1))
    }

    /// Returns the inverse of `self` or `None` if `self` is not invertible.
    ///
    /// # Edge cases
    /// If `self` is not invertible, returns `None`.
    #[must_use]
    pub const fn try_inverse(self) -> Option<Self> {
        let a: Vec3 = self.col0;
        let b: Vec3 = self.col1;
        let c: Vec3 = self.col2;

        let r0: Vec3 = b.cross(c);
        let r1: Vec3 = c.cross(a);
        let r2: Vec3 = a.cross(b);

        let det: f32 = r2.dot(c);

        if det.abs() < Self::EPSILON {
            return None;
        }
        let det_recip: f32 = det.recip();

        Some(Self::from_cols(
            Vec3::new(r0.x * det_recip, r1.x * det_recip, r2.x * det_recip),
            Vec3::new(r0.y * det_recip, r1.y * det_recip, r2.y * det_recip),
            Vec3::new(r0.z * det_recip, r1.z * det_recip, r2.z * det_recip),
        ))
    }

    /// Returns the inverse of `self`.
    ///
    /// # Panics
    /// Panics if `self` is not invertible.
    #[must_use]
    pub const fn inverse(self) -> Self {
        self.try_inverse().expect("matrix not invertible")
    }

    /// Returns `true` if `self` is invertible.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) to determine whether the determinant
    /// is sufficiently far from zero.
    #[inline]
    #[must_use]
    pub const fn is_invertible(self) -> bool {
        self.determinant().abs() >= Self::EPSILON
    }

    /// Returns `v` transformed by `self`.
    #[inline]
    #[must_use]
    pub const fn transform(self, v: Vec3) -> Vec3 {
        Vec3::new(
            self.col0.x * v.x + self.col1.x * v.y + self.col2.x * v.z,
            self.col0.y * v.x + self.col1.y * v.y + self.col2.y * v.z,
            self.col0.z * v.x + self.col1.z * v.y + self.col2.z * v.z,
        )
    }

    /// Returns `self` with the absolute value of each component.
    #[inline]
    #[must_use]
    pub const fn abs(self) -> Self {
        Self::from_cols(self.col0.abs(), self.col1.abs(), self.col2.abs())
    }

    /// Returns `self` with the reciprocal value of each component.
    #[inline]
    #[must_use]
    pub const fn recip(self) -> Self {
        Self::from_cols(self.col0.recip(), self.col1.recip(), self.col2.recip())
    }

    /// Returns `true` if `self` and `other` approximately represent the same matrix.
    ///
    /// Uses [`EPSILON`](Self::EPSILON) as the threshold.
    #[inline]
    #[must_use]
    pub const fn approx_eq(self, other: Self) -> bool {
        let a: [f32; 9] = self.to_array();
        let b: [f32; 9] = other.to_array();

        let mut i: usize = 0;
        while i < 9 {
            if (a[i] - b[i]).abs() >= Self::EPSILON {
                return false;
            }
            i += 1;
        }
        true
    }

    /// Returns `true` if all component of `self` are finite.
    #[inline]
    #[must_use]
    pub const fn is_finite(self) -> bool {
        let m: [f32; 9] = self.to_array();

        let mut i: usize = 0;
        while i < 9 {
            if !m[i].is_finite() {
                return false;
            }
            i += 1;
        }
        true
    }

    /// Returns `true` if any component of `self` is `NaN`.
    #[inline]
    #[must_use]
    pub const fn is_nan(self) -> bool {
        let m: [f32; 9] = self.to_array();

        let mut i: usize = 0;
        while i < 9 {
            if m[i].is_nan() {
                return true;
            }
            i += 1;
        }
        false
    }
}

impl Add for Mat3 {
    type Output = Self;

    /// Returns the component-wise sum of `self` and `rhs`.
    ///
    /// Equivalent to [`add`](Self::add()).
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        self.add(rhs)
    }
}

impl AddAssign for Mat3 {
    /// Sets self to the component-wise sum of `self` and `rhs`.
    ///
    /// Equivalent to [`add_assign`](Self::add_assign()).
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.add_assign(rhs);
    }
}

impl Sub for Mat3 {
    type Output = Self;

    /// Returns the component-wise difference of `self` and `rhs`.
    ///
    /// Equivalent to [`sub`](Self::sub()).
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        self.sub(rhs)
    }
}

impl SubAssign for Mat3 {
    /// Sets self to the component-wise difference of `self` and `rhs`.
    ///
    /// Equivalent to [`sub_assign`](Self::sub_assign()).
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        self.sub_assign(rhs);
    }
}

impl Mul for Mat3 {
    type Output = Self;

    /// Returns the matrix product of `self` and `rhs`.
    ///
    /// Equivalent to [`mul`](Self::mul()).
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        self.mul(rhs)
    }
}

impl MulAssign for Mat3 {
    /// Sets `self` to the matrix product of `self` and `rhs`.
    ///
    /// Equivalent to [`mul_assign`](Self::mul_assign()).
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        self.mul_assign(rhs);
    }
}

impl Mul<Vec3> for Mat3 {
    type Output = Vec3;

    /// Returns `rhs` transformed by `self`.
    ///
    /// Equivalent to [`mul_vec3`](Self::mul_vec3()).
    #[inline]
    fn mul(self, rhs: Vec3) -> Self::Output {
        self.mul_vec3(rhs)
    }
}

impl Mul<f32> for Mat3 {
    type Output = Self;

    /// Returns `self` with each component multiplied by `rhs`.
    ///
    /// Equivalent to [`mul_scalar`](Self::mul_scalar()).
    #[inline]
    fn mul(self, rhs: f32) -> Self::Output {
        self.mul_scalar(rhs)
    }
}

impl MulAssign<f32> for Mat3 {
    /// Sets `self` to `self` with each component multiplied by `rhs`.
    ///
    /// Equivalent to [`mul_assign_scalar`](Self::mul_assign_scalar()).
    #[inline]
    fn mul_assign(&mut self, rhs: f32) {
        self.mul_assign_scalar(rhs);
    }
}

impl Div<f32> for Mat3 {
    type Output = Self;

    /// Returns `self` with each component divided by `rhs`.
    ///
    /// Equivalent to [`div_scalar`](Self::div_scalar()).
    #[inline]
    fn div(self, rhs: f32) -> Self::Output {
        self.div_scalar(rhs)
    }
}

impl DivAssign<f32> for Mat3 {
    /// Sets `self` to `self` with each component divided by `rhs`.
    ///
    /// Equivalent to [`div_assign_scalar`](Self::div_assign_scalar()).
    #[inline]
    fn div_assign(&mut self, rhs: f32) {
        self.div_assign_scalar(rhs);
    }
}

impl Neg for Mat3 {
    type Output = Self;

    /// Returns `self` with negated components.
    ///
    /// Equivalent to [`neg`](Self::neg()).
    #[inline]
    fn neg(self) -> Self::Output {
        self.neg()
    }
}

impl AsRef<[f32; 9]> for Mat3 {
    /// Returns a reference to the components as `[col0, col1, col2]`,
    /// with each column as `[x, y, z]`.
    ///
    /// Equivalent to [`as_ref`](Self::as_ref()).
    ///
    /// # Safety
    /// Relies on `Mat3` being `#[repr(C)]`
    ///
    /// # Convention
    /// Array is in column-major order.
    #[inline]
    fn as_ref(&self) -> &[f32; 9] {
        self.as_ref()
    }
}

impl AsMut<[f32; 9]> for Mat3 {
    /// Returns a mutable reference to the components as `[col0, col1, col2]`,
    /// with each column as `[x, y, z]`.
    ///
    /// Equivalent to [`as_mut`](Self::as_mut()).
    ///
    /// # Safety
    /// Relies on `Mat3` being `#[repr(C)]`
    ///
    /// # Convention
    /// Array is in column-major order.
    #[inline]
    fn as_mut(&mut self) -> &mut [f32; 9] {
        self.as_mut()
    }
}

impl Display for Mat3 {
    /// Formats `self` as `[col0, col1, col2]`,
    /// with each column as `(x, y, z)`.
    ///
    /// Respects the precision of `f`.
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(p) = f.precision() {
            write!(
                f,
                "[{:.*}, {:.*}, {:.*}]",
                p, self.col0, p, self.col1, p, self.col2,
            )
        } else {
            write!(f, "[{}, {}, {}]", self.col0, self.col1, self.col2)
        }
    }
}

impl Default for Mat3 {
    /// Default is [`IDENTITY`](Self::IDENTITY).
    #[inline]
    fn default() -> Self {
        Self::IDENTITY
    }
}

impl From<[f32; 9]> for Mat3 {
    /// Creates a `Mat3` from a `[f32; 9]`, in column-major order:
    /// `[col0.x, col0.y, col0.z, col1.x, ..., col2.z]`.
    ///
    /// Equivalent to [`from_array`](Self::from_array()).
    #[inline]
    fn from(v: [f32; 9]) -> Self {
        Self::from_array(v)
    }
}

impl From<Mat3> for [f32; 9] {
    /// Returns a copy of the components as `[col0, col1, col2]`,
    /// with each column as `[x, y, z]`, in column-major order.
    ///
    /// Equivalent to [`to_array`](Mat3::to_array()).
    #[inline]
    fn from(v: Mat3) -> Self {
        v.to_array()
    }
}

impl From<Mat2> for Mat3 {
    /// Creates a `Mat3` from a `Mat2`, setting `col2` and `row2` to identity.
    ///
    /// Equivalent to [`from_mat2`](Self::from_mat2()).
    #[inline]
    fn from(v: Mat2) -> Self {
        Self::from_mat2(v)
    }
}

impl From<Mat4> for Mat3 {
    /// Creates a `Mat3` from a `Mat4`, discarding `col3` and `row3`.
    ///
    /// Equivalent to [`from_mat4`](Self::from_mat4()).
    #[inline]
    fn from(v: Mat4) -> Self {
        Self::from_mat4(v)
    }
}

impl From<Affine2> for Mat3 {
    /// Returns the equivalent `Mat3` of `v`.
    ///
    /// Equivalent to [`to_mat3`](Affine2::to_mat3()).
    #[inline]
    fn from(v: Affine2) -> Self {
        v.to_mat3()
    }
}

#[cfg(feature = "serde")]
impl serde::Serialize for Mat3 {
    /// Serializes as a `[f32; 9]` in column-major order.
    ///
    /// # Format
    /// Encoded as a flat 9-element array. Component order matches [`to_array`](Self::to_array()).
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        self.to_array().serialize(serializer)
    }
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Mat3 {
    /// Deserializes from a `[f32; 9]` in column-major order.
    ///
    /// # Format
    /// Decoded as a flat 9-element array. Component order matches [`from_array`](Self::from_array()).
    ///
    /// # Errors
    /// Returns an error if array is not exactly 9 elements.
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        <[f32; 9]>::deserialize(deserializer).map(Self::from_array)
    }
}

#[cfg(feature = "bytemuck")]
unsafe impl bytemuck::Zeroable for Mat3 {}

#[cfg(feature = "bytemuck")]
unsafe impl bytemuck::Pod for Mat3 {}
