llml 0.2.3

Implementation of basic math data types with high level frontend and low level backend
arm_use!();
use core::mem::transmute;
use std::ptr::{addr_of};
use std::{ops::{Add, Sub, Mul, Div, Neg}};
use crate::vec::EucVecd2;

macro_rules! impl_vec4_vv {
    ($target:ident, $ty:ident, $tag:ident) => {
        impl_vec4_vv!(
            $target, $ty, $tag,
            Add, add, +,
            Sub, sub, -,
            Mul, mul, *,
            Div, div, /
        );

        impl $target {
            #[inline]
            pub fn new (a: [$ty;4]) -> Self {
                Self(EucVecd2::new([a[0], a[1]]), EucVecd2::new([a[2], a[3]]))
            }

            #[inline]
            pub fn from_scal (a: $ty) -> Self {
                Self(EucVecd2::from_scal(a), EucVecd2::from_scal(a))
            }

            #[inline(always)]
            pub fn x (&self) -> $ty {
                self.0.x()
            }

            #[inline(always)]
            pub fn y (&self) -> $ty {
                self.0.y()
            }

            #[inline(always)]
            pub fn z (&self) -> $ty {
                self.1.x()
            }

            #[inline(always)]
            pub fn w (&self) -> $ty {
                self.1.y()
            }

            #[inline(always)]
            pub fn abs (self) -> Self {
                Self(self.0.abs(), self.1.abs())
            }

            #[inline(always)]
            pub fn sum (self) -> $ty {
                self.0.sum() + self.1.sum()
            }

            #[inline(always)]
            pub fn dot (self, rhs: Self) -> $ty {
                (self * rhs).sum()
            }

            #[inline(always)]
            #[deprecated(since="0.2.0", note="use ```self.dot(self)``` instead")]
            pub fn norm2 (self) -> $ty {
                self.dot(self)
            }

            #[inline(always)]
            pub fn norm (self) -> $ty {
                self.dot(self).sqrt()
            }

            #[inline(always)]
            pub fn unit (self) -> Self {
                self / self.norm()
            }

            #[inline(always)]
            pub fn sqrt (self) -> Self {
                Self(self.0.sqrt(), self.1.sqrt())
            }

            #[inline(always)]
            pub fn sqrt_fast (self) -> Self {
                self.sqrt()
            }
        }

        impl Neg for $target {
            type Output = Self;

            #[inline(always)]
            fn neg (self) -> Self::Output {
                Self(-self.0, -self.1)
            }
        }

        impl PartialEq for $target {
            #[inline(always)]
            fn eq (&self, rhs: &Self) -> bool {
                self.1 == rhs.1 && self.0 == rhs.0
            }
        }

        impl Into<[$ty;4]> for $target {
            #[inline(always)]
            fn into (self) -> [$ty;4] {
                unsafe { transmute(self) }
            }
        }
    };

    ($target:ident, $ty:ident, $tag:ident, $($trait:ident, $fun:ident, $sy:tt),+) => {
        $(
            impl $trait for $target {
                type Output = Self;

                #[inline(always)]
                fn $fun (self, rhs: Self) -> Self::Output {
                    Self(self.0 $sy rhs.0, self.1 $sy rhs.1)
                }
            }

            impl $trait<$ty> for $target {
                type Output = Self;

                #[inline(always)]
                fn $fun (self, rhs: $ty) -> Self::Output {
                    Self(self.0 $sy rhs, self.1 $sy rhs)
                }
            }

            impl $trait<$target> for $ty {
                type Output = $target;

                #[inline(always)]
                fn $fun (self, rhs: $target) -> Self::Output {
                    $target(self $sy rhs.0, self $sy rhs.1)
                }
            }
        )*
    };
}

wrap!(EucVecf4, float32x4_t);
impl_vec4!(EucVecf4, f32, q);

#[derive(Clone, Copy)]
#[repr(C, align(16))]
pub struct EucVecd4 (pub(crate) EucVecd2, pub(crate) EucVecd2);
impl Eq for EucVecd4 {}
impl_vec4_vv!(EucVecd4, f64, q);

impl Into<EucVecf4> for EucVecd4 {
    #[inline(always)]
    fn into (self) -> EucVecf4 {
        unsafe {
            let xy = vcvt_f32_f64(self.0.0);
            let zw = vcvt_f32_f64(self.1.0);
            EucVecf4(vcombine_f32(xy, zw))
        }
    }
}

impl Into<EucVecd4> for EucVecf4 {
    #[inline(always)]
    fn into(self) -> EucVecd4 {
        unsafe {
            let xy = vcvt_f64_f32(vget_low_f32(self.0));
            let zw = vcvt_f64_f32(vget_high_f32(self.0));
            EucVecd4(EucVecd2(xy), EucVecd2(zw))
        }
    }
}