gemath 0.1.0

Type-safe game math with type-level units/spaces, typed angles, and explicit fallible ops (plus optional geometry/collision).
Documentation
use half::f16;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};

#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
#[repr(transparent)] // Ensure it has the same memory layout as f16
pub struct Half(pub f16);

impl Half {
    #[inline]
    pub fn new(value: f16) -> Self {
        Self(value)
    }

    #[inline]
    pub fn from_f32(value: f32) -> Self {
        Self(f16::from_f32(value))
    }

    #[inline]
    pub fn to_f32(self) -> f32 {
        self.0.to_f32()
    }
}

// Implement From traits for easier conversions
impl From<f32> for Half {
    #[inline]
    fn from(value: f32) -> Self {
        Half::from_f32(value)
    }
}

impl From<Half> for f32 {
    #[inline]
    fn from(value: Half) -> Self {
        value.to_f32()
    }
}

impl From<f16> for Half {
    #[inline]
    fn from(value: f16) -> Self {
        Half::new(value)
    }
}

impl From<Half> for f16 {
    #[inline]
    fn from(value: Half) -> Self {
        value.0
    }
}

// Arithmetic operations for Half
impl Add for Half {
    type Output = Self;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        Self(self.0 + rhs.0)
    }
}

impl AddAssign for Half {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.0 = self.0 + rhs.0;
    }
}

impl Sub for Half {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        Self(self.0 - rhs.0)
    }
}

impl SubAssign for Half {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        self.0 = self.0 - rhs.0;
    }
}

impl Mul for Half {
    type Output = Self;
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        Self(self.0 * rhs.0)
    }
}

impl MulAssign for Half {
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        self.0 = self.0 * rhs.0;
    }
}

impl Div for Half {
    type Output = Self;
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        Self(self.0 / rhs.0)
    }
}

impl DivAssign for Half {
    #[inline]
    fn div_assign(&mut self, rhs: Self) {
        self.0 = self.0 / rhs.0;
    }
}

/// Converts a slice of `f32` to a `Vec<Half>`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn halfs_from_f32_slice(slice: &[f32]) -> Vec<Half> {
    slice.iter().map(|&v| Half::from_f32(v)).collect()
}

/// Converts a slice of `Half` to a `Vec<f32>`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn f32s_from_half_slice(slice: &[Half]) -> Vec<f32> {
    slice.iter().map(|&h| h.to_f32()).collect()
}

/// Converts a slice of `f16` to a `Vec<Half>`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn halfs_from_f16_slice(slice: &[f16]) -> Vec<Half> {
    slice.iter().map(|&v| Half::new(v)).collect()
}

/// Converts a slice of `Half` to a `Vec<f16>`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn f16s_from_half_slice(slice: &[Half]) -> Vec<f16> {
    slice.iter().map(|&h| h.0).collect()
}

/// Converts an array of f32 to an array of Half.
pub fn halfs_from_f32_array<const N: usize>(arr: [f32; N]) -> [Half; N] {
    let mut out: [Half; N] = [Half::from_f32(0.0); N];
    for (i, v) in arr.iter().enumerate() {
        out[i] = Half::from_f32(*v);
    }
    out
}

/// Converts an array of Half to an array of f32.
pub fn f32s_from_half_array<const N: usize>(arr: [Half; N]) -> [f32; N] {
    let mut out: [f32; N] = [0.0; N];
    for (i, h) in arr.iter().enumerate() {
        out[i] = h.to_f32();
    }
    out
}

/// Converts an array of f16 to an array of Half.
pub fn halfs_from_f16_array<const N: usize>(arr: [f16; N]) -> [Half; N] {
    let mut out: [Half; N] = [Half::from_f32(0.0); N];
    for (i, v) in arr.iter().enumerate() {
        out[i] = Half::new(*v);
    }
    out
}

/// Converts an array of Half to an array of f16.
pub fn f16s_from_half_array<const N: usize>(arr: [Half; N]) -> [f16; N] {
    let mut out: [f16; N] = [f16::from_f32(0.0); N];
    for (i, h) in arr.iter().enumerate() {
        out[i] = h.0;
    }
    out
}