use approx::RelativeEq;
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
use std::mem;
use std::ops::{Deref, Neg};
#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::{SubsetOf, ComplexField};
use alga::linear::NormedSpace;
#[repr(transparent)]
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
pub struct Unit<T> {
value: T,
}
#[cfg(feature = "serde-serialize")]
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")]
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 })
}
}
#[cfg(feature = "abomonation-serialize")]
impl<T: Abomonation> Abomonation for Unit<T> {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
self.value.entomb(writer)
}
fn extent(&self) -> usize {
self.value.extent()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.value.exhume(bytes)
}
}
impl<T: NormedSpace> 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::RealField) -> Option<Self> {
Self::try_new_and_get(value, min_norm).map(|res| res.0)
}
#[inline]
pub fn new_and_get(mut value: T) -> (Self, T::RealField) {
let n = value.normalize_mut();
(Unit { value: value }, n)
}
#[inline]
pub fn try_new_and_get(mut value: T, min_norm: T::RealField) -> Option<(Self, T::RealField)> {
if let Some(n) = value.try_normalize_mut(min_norm) {
Some((Unit { value: value }, n))
} else {
None
}
}
#[inline]
pub fn renormalize(&mut self) -> T::RealField {
self.value.normalize_mut()
}
#[inline]
pub fn renormalize_fast(&mut self) {
let sq_norm = self.value.norm_squared();
let _3: T::RealField = crate::convert(3.0);
let _0_5: T::RealField = crate::convert(0.5);
self.value *= T::ComplexField::from_real(_0_5 * (_3 - sq_norm));
}
}
impl<T> Unit<T> {
#[inline]
pub fn new_unchecked(value: T) -> Self {
Unit { value: value }
}
#[inline]
pub fn from_ref_unchecked<'a>(value: &'a T) -> &'a Self {
unsafe { mem::transmute(value) }
}
#[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 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: NormedSpace> SubsetOf<T> for Unit<T>
where T::Field: RelativeEq
{
#[inline]
fn to_superset(&self) -> T {
self.clone().into_inner()
}
#[inline]
fn is_in_subset(value: &T) -> bool {
relative_eq!(value.norm_squared(), crate::one())
}
#[inline]
unsafe fn from_superset_unchecked(value: &T) -> Self {
Unit::new_normalize(value.clone()) }
}
impl<T: Neg> Neg for Unit<T> {
type Output = Unit<T::Output>;
#[inline]
fn neg(self) -> Self::Output {
Self::Output::new_unchecked(-self.value)
}
}
impl<T> Deref for Unit<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { mem::transmute(self) }
}
}