#![cfg_attr(feature = "rkyv-serialize", allow(unsafe_op_in_unsafe_fn))]
use std::fmt;
use std::ops::Deref;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::allocator::Allocator;
use crate::base::DefaultAllocator;
use crate::storage::RawStorage;
use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField};
#[cfg(feature = "rkyv-serialize")]
use rkyv::bytecheck;
#[repr(transparent)]
#[derive(Clone, Hash, Copy)]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize),
archive(
as = "Unit<T::Archived>",
bound(archive = "
T: rkyv::Archive,
")
)
)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Unit<T> {
pub(crate) value: T,
}
impl<T: fmt::Debug> fmt::Debug for Unit<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.value.fmt(formatter)
}
}
#[cfg(feature = "bytemuck")]
unsafe impl<T> bytemuck::Zeroable for Unit<T> where T: bytemuck::Zeroable {}
#[cfg(feature = "bytemuck")]
unsafe impl<T> bytemuck::Pod for Unit<T> where T: bytemuck::Pod {}
#[cfg(feature = "serde-serialize-no-std")]
impl<T: Serialize> Serialize for Unit<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.value.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize-no-std")]
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Unit<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer).map(|x| Unit { value: x })
}
}
impl<T, R, C, S> PartialEq for Unit<Matrix<T, R, C, S>>
where
T: Scalar + PartialEq,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
#[inline]
fn eq(&self, rhs: &Self) -> bool {
self.value.eq(&rhs.value)
}
}
impl<T, R, C, S> Eq for Unit<Matrix<T, R, C, S>>
where
T: Scalar + Eq,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
}
pub trait Normed {
type Norm: SimdRealField;
fn norm(&self) -> Self::Norm;
fn norm_squared(&self) -> Self::Norm;
fn scale_mut(&mut self, n: Self::Norm);
fn unscale_mut(&mut self, n: Self::Norm);
}
impl<T: Normed> Unit<T> {
#[inline]
pub fn new_normalize(value: T) -> Self {
Self::new_and_get(value).0
}
#[inline]
pub fn try_new(value: T, min_norm: T::Norm) -> Option<Self>
where
T::Norm: RealField,
{
Self::try_new_and_get(value, min_norm).map(|res| res.0)
}
#[inline]
pub fn new_and_get(mut value: T) -> (Self, T::Norm) {
let n = value.norm();
value.unscale_mut(n.clone());
(Unit { value }, n)
}
#[inline]
pub fn try_new_and_get(mut value: T, min_norm: T::Norm) -> Option<(Self, T::Norm)>
where
T::Norm: RealField,
{
let sq_norm = value.norm_squared();
if sq_norm > min_norm.clone() * min_norm {
let n = sq_norm.simd_sqrt();
value.unscale_mut(n.clone());
Some((Unit { value }, n))
} else {
None
}
}
#[inline]
pub fn renormalize(&mut self) -> T::Norm {
let n = self.norm();
self.value.unscale_mut(n.clone());
n
}
#[inline]
pub fn renormalize_fast(&mut self) {
let sq_norm = self.value.norm_squared();
let three: T::Norm = crate::convert(3.0);
let half: T::Norm = crate::convert(0.5);
self.value.scale_mut(half * (three - sq_norm));
}
}
impl<T> Unit<T> {
#[inline]
pub const fn new_unchecked(value: T) -> Self {
Unit { value }
}
#[inline]
pub const fn from_ref_unchecked(value: &T) -> &Self {
unsafe { &*(value as *const T as *const Self) }
}
#[inline]
pub fn into_inner(self) -> T {
self.value
}
#[deprecated(note = "use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> T {
self.value
}
#[inline]
pub const fn as_mut_unchecked(&mut self) -> &mut T {
&mut self.value
}
}
impl<T> AsRef<T> for Unit<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T> Deref for Unit<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &*(self as *const Self as *const T) }
}
}
impl<T: Scalar + simba::simd::PrimitiveSimdValue, R: Dim, C: Dim>
From<[Unit<OMatrix<T::Element, R, C>>; 2]> for Unit<OMatrix<T, R, C>>
where
T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
T::Element: Scalar,
DefaultAllocator: Allocator<R, C>,
{
#[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 2]) -> Self {
Self::new_unchecked(OMatrix::from([
arr[0].clone().into_inner(),
arr[1].clone().into_inner(),
]))
}
}
impl<T: Scalar + simba::simd::PrimitiveSimdValue, R: Dim, C: Dim>
From<[Unit<OMatrix<T::Element, R, C>>; 4]> for Unit<OMatrix<T, R, C>>
where
T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
T::Element: Scalar,
DefaultAllocator: Allocator<R, C>,
{
#[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 4]) -> Self {
Self::new_unchecked(OMatrix::from([
arr[0].clone().into_inner(),
arr[1].clone().into_inner(),
arr[2].clone().into_inner(),
arr[3].clone().into_inner(),
]))
}
}
impl<T: Scalar + simba::simd::PrimitiveSimdValue, R: Dim, C: Dim>
From<[Unit<OMatrix<T::Element, R, C>>; 8]> for Unit<OMatrix<T, R, C>>
where
T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
T::Element: Scalar,
DefaultAllocator: Allocator<R, C>,
{
#[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 8]) -> Self {
Self::new_unchecked(OMatrix::from([
arr[0].clone().into_inner(),
arr[1].clone().into_inner(),
arr[2].clone().into_inner(),
arr[3].clone().into_inner(),
arr[4].clone().into_inner(),
arr[5].clone().into_inner(),
arr[6].clone().into_inner(),
arr[7].clone().into_inner(),
]))
}
}
impl<T: Scalar + simba::simd::PrimitiveSimdValue, R: Dim, C: Dim>
From<[Unit<OMatrix<T::Element, R, C>>; 16]> for Unit<OMatrix<T, R, C>>
where
T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
T::Element: Scalar,
DefaultAllocator: Allocator<R, C>,
{
#[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 16]) -> Self {
Self::new_unchecked(OMatrix::from([
arr[0].clone().into_inner(),
arr[1].clone().into_inner(),
arr[2].clone().into_inner(),
arr[3].clone().into_inner(),
arr[4].clone().into_inner(),
arr[5].clone().into_inner(),
arr[6].clone().into_inner(),
arr[7].clone().into_inner(),
arr[8].clone().into_inner(),
arr[9].clone().into_inner(),
arr[10].clone().into_inner(),
arr[11].clone().into_inner(),
arr[12].clone().into_inner(),
arr[13].clone().into_inner(),
arr[14].clone().into_inner(),
arr[15].clone().into_inner(),
]))
}
}