glam_det 2.0.0-beta.2

A simple and fast 3D math library for games and graphics.
// Copyright (C) 2020-2025 glam-det authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use core::{
    marker::Sized,
    ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub},
};

/// Lane-wise generalization of `bool` for SIMD booleans.
///
/// This trait implemented by `bool` as well as SIMD boolean types like `bool32x4`.
/// It is designed to abstract the behavior of booleans, so it can work with multi-lane boolean
/// values in an AoSoA setting.
pub trait Bool:
    Copy
    + BitAnd<Self, Output = Self>
    + BitOr<Self, Output = Self>
    + BitXor<Self, Output = Self>
    + Not<Output = Self>
{
    const FALSE: Self;
    const TRUE: Self;

    /// A bit mask representing the boolean state of each lane of `self`.
    ///
    /// The `i-th` bit of the result is `1` iff. the `i-th` lane of `self` is `true`.
    fn bitmask(self) -> u64;

    /// Are all vector lanes true?
    fn all(self) -> bool;

    /// Is any vector lane true?
    fn any(self) -> bool;

    /// Are all vector lanes false?
    fn none(self) -> bool;
}

/// Base trait for every SIMD types.
pub trait Num: Sized + Clone {
    /// The type of the elements of each lane of this SIMD value.
    type Element;
    /// Type of the result of comparing two SIMD values like `self`.
    type Bool: Bool;

    /// The number of lanes of this SIMD value.
    fn lanes() -> usize;

    /// Initializes an SIMD value with each lane set to `val`.
    fn splat(val: Self::Element) -> Self;

    /// Extracts the i-th lane of `self`.
    ///
    /// # Panics
    ///
    /// Will panic if `i >= Self::lanes()`.
    fn extract(&self, i: usize) -> Self::Element;

    /// Extracts the i-th lane of `self` without bound-checking.
    ///
    /// # Safety
    ///
    /// Behaviour unpredictable when index out of bound.
    unsafe fn extract_unchecked(&self, i: usize) -> Self::Element;

    /// Replaces the i-th lane of `self` by `val`.
    ///
    /// # Panics
    ///
    /// Will panic if `i >= Self::lanes()`.
    fn replace(&mut self, i: usize, val: Self::Element);

    /// Replaces the i-th lane of `self` by `val` without bound-checking.
    ///
    /// # Safety
    ///
    /// Behaviour unpredictable when index out of bound.
    unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element);

    /// Merges `self` and `other` depending on the lanes of `cond`.
    ///
    /// For each lane of `cond` with bits set to 1, the result's will contain the value of the lane of `self`.
    /// For each lane of `cond` with bits set to 0, the result's will contain the value of the lane of `other`.
    fn select(self, cond: Self::Bool, other: Self) -> Self;

    /// Applies a function to each lane of `self`.
    ///
    /// Note that, while convenient, this method can be extremely slow as this
    /// requires to extract each lane of `self` and then combine them again into
    /// a new SIMD value.
    #[inline]
    fn map_lanes(self, f: impl Fn(Self::Element) -> Self::Element) -> Self {
        let mut result = self.clone();

        for i in 0..Self::lanes() {
            unsafe { result.replace_unchecked(i, f(self.extract_unchecked(i))) }
        }

        result
    }

    /// Applies a function to each lane of `self` paired with the corresponding lane of `b`.
    ///
    /// Note that, while convenient, this method can be extremely slow as this
    /// requires to extract each lane of `self` and then combine them again into
    /// a new SIMD value.
    #[inline]
    fn zip_map_lanes(
        self,
        b: Self,
        f: impl Fn(Self::Element, Self::Element) -> Self::Element,
    ) -> Self {
        let mut result = self.clone();

        for i in 0..Self::lanes() {
            unsafe {
                let a = self.extract_unchecked(i);
                let b = b.extract_unchecked(i);
                result.replace_unchecked(i, f(a, b))
            }
        }

        result
    }
}

/// Lane-wise generalization of the standard `PartialOrd` for SIMD values.
pub trait PartialOrdEx: Num {
    /// Lanewise _greater than_ `>` comparison.
    fn gt(self, other: Self) -> Self::Bool;
    /// Lanewise _less than_ `<` comparison.
    fn lt(self, other: Self) -> Self::Bool;
    /// Lanewise _greater or equal_ `>=` comparison.
    fn ge(self, other: Self) -> Self::Bool;
    /// Lanewise _less or equal_ `<=` comparison.
    fn le(self, other: Self) -> Self::Bool;
    /// Lanewise _equal_ `==` comparison.
    fn eq(self, other: Self) -> Self::Bool;
    /// Lanewise _not equal_ `!=` comparison.
    fn ne(self, other: Self) -> Self::Bool;

    /// Lanewise max value.
    fn max(self, other: Self) -> Self;
    /// Lanewise min value.
    fn min(self, other: Self) -> Self;
    /// Clamps each lane of `self` between the corresponding lane of `min` and `max`.
    fn clamp(self, min: Self, max: Self) -> Self;
}

pub trait Signed: Sized + Num + core::ops::Neg<Output = Self> {
    fn absf(self) -> Self;
    fn signumf(self) -> Self;
}

pub trait Float: Num + Copy + core::ops::Neg<Output = Self> {
    fn asinf(self) -> Self;
    fn acosf(self) -> Self;
    fn atanf(self) -> Self;
    fn atan2f(self, x: Self) -> Self;
    fn ceilf(self) -> Self;
    fn copysignf(self, sign: Self) -> Self;
    fn expf(self) -> Self;
    fn floorf(self) -> Self;
    fn is_finite(self) -> Self::Bool;
    fn is_nan(self) -> Self::Bool;
    fn mul_addf(self, b: Self, c: Self) -> Self;
    fn powif(self, n: i32) -> Self;
    fn powff(self, n: Self) -> Self;
    fn recip(self) -> Self;
    fn roundf(self) -> Self;
    fn sqrtf(self) -> Self;
    fn sinf(self) -> Self;
    fn cosf(self) -> Self;
    fn sin_cosf(self) -> (Self, Self);
    fn tanf(self) -> Self;
    fn minf(self, other: Self) -> Self;
    fn maxf(self, other: Self) -> Self;
}

pub trait NumConstEx: Sized {
    const ZERO: Self;
    const ONE: Self;
    const TWO: Self;
}

pub trait FloatConstEx: Sized {
    const NEG_ONE: Self;
    const TWO: Self;
    const HALF: Self;
}

pub trait NanConstEx: Sized {
    const NAN: Self;
}

pub trait NumEx:
    Num
    + NumConstEx
    + Copy
    + Clone
    + PartialEq
    + PartialOrdEx
    + Add<Output = Self>
    + Div<Output = Self>
    + Mul<Output = Self>
    + Sub<Output = Self>
    + Rem<Output = Self>
    + Add<Self::Element, Output = Self>
    + Div<Self::Element, Output = Self>
    + Mul<Self::Element, Output = Self>
    + Sub<Self::Element, Output = Self>
    + Rem<Self::Element, Output = Self>
{
}

pub trait SignedEx: Signed + NumEx {}

pub trait IntegerShiftOps<Rhs>: Sized + Shl<Rhs, Output = Self> + Shr<Rhs, Output = Self> {}

pub trait IntegerBitOps:
    Sized + Not<Output = Self> + BitAnd<Output = Self> + BitOr<Output = Self> + BitXor<Output = Self>
{
}