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 super::{
    common_types::ConstUnionHack128bit,
    macros::*,
    num_traits::{Bool, Num},
    u32x4,
};
#[cfg(not(feature = "scalar-math"))]
use super::{f32x4, i32x4};
use auto_ops_det::impl_op_ex;
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::ops;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "scalar-math")]
type Inner = [u32; 4];
#[cfg(not(feature = "scalar-math"))]
type Inner = crate::wide::u32x4;

/// A wide bool type with SIMD support.
#[allow(non_camel_case_types)]
#[cfg_attr(
    all(
        feature = "std",
        not(feature = "libm_force"),
        not(feature = "scalar-math")
    ),
    repr(transparent)
)]
#[cfg_attr(
    any(
        feature = "libm_force",
        feature = "scalar-math",
        all(feature = "libm_fallback", not(feature = "std"))
    ),
    repr(align(16))
)]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct bool32x4(pub(crate) Inner);

#[cfg(not(feature = "scalar-math"))]
impl_type_cast_methods!(bool32x4, f32x4, cast_f32x4, cast_bool32x4);
#[cfg(not(feature = "scalar-math"))]
impl_type_cast_methods!(bool32x4, i32x4, cast_i32x4, cast_bool32x4);

impl_type_cast_methods!(bool32x4, u32x4, cast_u32x4, cast_bool32x4);

#[cfg(feature = "scalar-math")]
impl bool32x4 {
    #[inline]
    fn zip_map(self, rhs: Self, f: impl Fn(bool, bool) -> bool) -> Self {
        let arr: [bool; 4] = self.into();
        let rhs: [bool; 4] = rhs.into();
        Self::from([
            f(arr[0], rhs[0]),
            f(arr[1], rhs[1]),
            f(arr[2], rhs[2]),
            f(arr[3], rhs[3]),
        ])
    }
}

impl Default for bool32x4 {
    fn default() -> Self {
        bool32x4::from([false; 4])
    }
}

impl From<[bool; 4]> for bool32x4 {
    #[inline]
    fn from(vals: [bool; 4]) -> Self {
        let bits = [0u32, u32::MAX];
        bool32x4(add_into!([
            bits[vals[0] as usize],
            bits[vals[1] as usize],
            bits[vals[2] as usize],
            bits[vals[3] as usize],
        ]))
    }
}

impl From<bool32x4> for [bool; 4] {
    #[inline]
    fn from(val: bool32x4) -> Self {
        let a: &[u32; 4] = as_array_ref!(val.0);
        [a[0] != 0u32, a[1] != 0u32, a[2] != 0u32, a[3] != 0u32]
    }
}

impl Num for bool32x4 {
    type Element = bool;
    type Bool = Self;

    #[inline]
    fn lanes() -> usize {
        4
    }

    #[inline]
    fn splat(val: bool) -> Self {
        let results = [bool32x4::FALSE, bool32x4::TRUE];
        results[val as usize]
    }

    #[inline]
    fn extract(&self, i: usize) -> Self::Element {
        as_array_ref!(self.0)[i] != 0u32
    }

    #[inline]
    unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
        *as_array_ref!(self.0).get_unchecked(i) != 0u32
    }

    #[inline]
    fn replace(&mut self, i: usize, val: Self::Element) {
        let vals = [0u32, u32::MAX];
        let arr = as_array_mut!(self.0);
        arr[i] = vals[val as usize];
    }

    #[inline]
    unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
        let vals = [0u32, u32::MAX];
        let arr = as_array_mut!(self.0);
        *arr.get_unchecked_mut(i) = vals[val as usize];
    }

    #[inline]
    fn select(self, cond: Self::Bool, other: Self) -> Self {
        #[cfg(feature = "scalar-math")]
        {
            let mut arr = [0_u32; 4];
            for (i, xi) in arr.iter_mut().enumerate() {
                *xi = if cond.0[i] == u32::MAX {
                    self.0[i]
                } else {
                    other.0[i]
                };
            }
            Self(arr)
        }
        #[cfg(not(feature = "scalar-math"))]
        {
            bool32x4(cond.0.blend(self.0, other.0))
        }
    }
}

impl_wide_partial_eq!(bool32x4);
impl_wide_bit_ops!(bool32x4);

impl Bool for bool32x4 {
    #[cfg(feature = "scalar-math")]
    const FALSE: bool32x4 = bool32x4([0_u32; 4]);
    #[cfg(feature = "scalar-math")]
    const TRUE: bool32x4 = bool32x4([u32::MAX; 4]);
    #[cfg(not(feature = "scalar-math"))]
    const FALSE: bool32x4 = bool32x4(crate::wide::u32x4::ZERO);
    #[cfg(not(feature = "scalar-math"))]
    const TRUE: bool32x4 = bool32x4(crate::wide::u32x4::MAX);

    #[inline]
    fn bitmask(self) -> u64 {
        let arr = as_array_ref!(self.0);
        ((arr[0] != 0u32) as u64)
            | (((arr[1] != 0u32) as u64) << 1)
            | (((arr[2] != 0u32) as u64) << 2)
            | (((arr[3] != 0u32) as u64) << 3)
    }

    #[inline]
    fn all(self) -> bool {
        self == bool32x4::TRUE
    }

    #[inline]
    fn any(self) -> bool {
        self != bool32x4::FALSE
    }

    #[inline]
    fn none(self) -> bool {
        self == bool32x4::FALSE
    }
}

#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for bool32x4 {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let arr: [bool; 4] = (*self).into();
        write!(f, "{:?}", arr)
    }
}