+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
+#[repr(transparent)]
+pub struct Value<T>(pub T);
+
+macro_rules! impl_convert_from {
+ ($first:ident $(, $ty:ident)*) => {
+ $(
+ impl ConvertFrom<Value<$first>> for Value<$ty> {
+ fn cvt_from(v: Value<$first>) -> Self {
+ Value(ConvertFrom::cvt_from(v.0))
+ }
+ }
+ impl ConvertFrom<Value<$ty>> for Value<$first> {
+ fn cvt_from(v: Value<$ty>) -> Self {
+ Value(ConvertFrom::cvt_from(v.0))
+ }
+ }
+ )*
+ impl_convert_from![$($ty),*];
+ };
+ () => {
+ };
+}
+
+impl_convert_from![u8, i8, u16, i16, F16, u32, i32, u64, i64, f32, f64];
+
+macro_rules! impl_bit_ops {
+ ($ty:ident) => {
+ impl BitAnd for Value<$ty> {
+ type Output = Self;
+
+ fn bitand(self, rhs: Self) -> Self {
+ Value(self.0 & rhs.0)
+ }
+ }
+
+ impl BitOr for Value<$ty> {
+ type Output = Self;
+
+ fn bitor(self, rhs: Self) -> Self {
+ Value(self.0 | rhs.0)
+ }
+ }
+
+ impl BitXor for Value<$ty> {
+ type Output = Self;
+
+ fn bitxor(self, rhs: Self) -> Self {
+ Value(self.0 ^ rhs.0)
+ }
+ }
+
+ impl Not for Value<$ty> {
+ type Output = Self;
+
+ fn not(self) -> Self {
+ Value(!self.0)
+ }
+ }
+
+ impl BitAndAssign for Value<$ty> {
+ fn bitand_assign(&mut self, rhs: Self) {
+ self.0 &= rhs.0;
+ }
+ }
+
+ impl BitOrAssign for Value<$ty> {
+ fn bitor_assign(&mut self, rhs: Self) {
+ self.0 |= rhs.0;
+ }
+ }
+
+ impl BitXorAssign for Value<$ty> {
+ fn bitxor_assign(&mut self, rhs: Self) {
+ self.0 ^= rhs.0;
+ }
+ }
+ };
+}
+
+macro_rules! impl_wrapping_int_ops {
+ ($ty:ident) => {
+ impl Add for Value<$ty> {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_add(rhs.0))
+ }
+ }
+
+ impl Sub for Value<$ty> {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_sub(rhs.0))
+ }
+ }
+
+ impl Mul for Value<$ty> {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_mul(rhs.0))
+ }
+ }
+
+ impl Div for Value<$ty> {
+ type Output = Self;
+
+ fn div(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_div(rhs.0))
+ }
+ }
+
+ impl Rem for Value<$ty> {
+ type Output = Self;
+
+ fn rem(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_rem(rhs.0))
+ }
+ }
+
+ impl Shl for Value<$ty> {
+ type Output = Self;
+
+ fn shl(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_shl(rhs.0 as u32))
+ }
+ }
+
+ impl Shr for Value<$ty> {
+ type Output = Self;
+
+ fn shr(self, rhs: Self) -> Self {
+ Value(self.0.wrapping_shr(rhs.0 as u32))
+ }
+ }
+
+ impl Neg for Value<$ty> {
+ type Output = Self;
+
+ fn neg(self) -> Self {
+ Value(self.0.wrapping_neg())
+ }
+ }
+
+ impl AddAssign for Value<$ty> {
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add(rhs);
+ }
+ }
+
+ impl SubAssign for Value<$ty> {
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.sub(rhs);
+ }
+ }
+
+ impl MulAssign for Value<$ty> {
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul(rhs);
+ }
+ }
+
+ impl DivAssign for Value<$ty> {
+ fn div_assign(&mut self, rhs: Self) {
+ *self = self.div(rhs);
+ }
+ }
+
+ impl RemAssign for Value<$ty> {
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = self.rem(rhs);
+ }
+ }
+
+ impl ShlAssign for Value<$ty> {
+ fn shl_assign(&mut self, rhs: Self) {
+ *self = self.shl(rhs);
+ }
+ }
+
+ impl ShrAssign for Value<$ty> {
+ fn shr_assign(&mut self, rhs: Self) {
+ *self = self.shr(rhs);
+ }
+ }
+ };
+}
+macro_rules! impl_int {
+ ($ty:ident) => {
+ impl_bit_ops!($ty);
+ impl_wrapping_int_ops!($ty);
+ impl Int for Value<$ty> {
+ fn leading_zeros(self) -> Self {
+ Value(self.0.leading_zeros() as $ty)
+ }
+ fn leading_ones(self) -> Self {
+ Value(self.0.leading_ones() as $ty)
+ }
+ fn trailing_zeros(self) -> Self {
+ Value(self.0.trailing_zeros() as $ty)
+ }
+ fn trailing_ones(self) -> Self {
+ Value(self.0.trailing_ones() as $ty)
+ }
+ fn count_zeros(self) -> Self {
+ Value(self.0.count_zeros() as $ty)
+ }
+ fn count_ones(self) -> Self {
+ Value(self.0.count_ones() as $ty)
+ }
+ }
+ };
+}
+
+macro_rules! impl_uint {
+ ($($ty:ident),*) => {
+ $(
+ impl_int!($ty);
+ impl UInt for Value<$ty> {}
+ )*
+ };
+}
+
+impl_uint![u8, u16, u32, u64];
+
+macro_rules! impl_sint {
+ ($($ty:ident),*) => {
+ $(
+ impl_int!($ty);
+ impl SInt for Value<$ty> {}
+ )*
+ };
+}
+
+impl_sint![i8, i16, i32, i64];
+
+macro_rules! impl_float_ops {
+ ($ty:ident) => {
+ impl Add for Value<$ty> {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ Value(self.0.add(rhs.0))
+ }
+ }
+
+ impl Sub for Value<$ty> {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ Value(self.0.sub(rhs.0))
+ }
+ }
+
+ impl Mul for Value<$ty> {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self {
+ Value(self.0.mul(rhs.0))
+ }
+ }
+
+ impl Div for Value<$ty> {
+ type Output = Self;
+
+ fn div(self, rhs: Self) -> Self {
+ Value(self.0.div(rhs.0))
+ }
+ }
+
+ impl Rem for Value<$ty> {
+ type Output = Self;
+
+ fn rem(self, rhs: Self) -> Self {
+ Value(self.0.rem(rhs.0))
+ }
+ }
+
+ impl Neg for Value<$ty> {
+ type Output = Self;
+
+ fn neg(self) -> Self {
+ Value(self.0.neg())
+ }
+ }
+
+ impl AddAssign for Value<$ty> {
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add(rhs);
+ }
+ }
+
+ impl SubAssign for Value<$ty> {
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.sub(rhs);
+ }
+ }
+
+ impl MulAssign for Value<$ty> {
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul(rhs);
+ }
+ }
+
+ impl DivAssign for Value<$ty> {
+ fn div_assign(&mut self, rhs: Self) {
+ *self = self.div(rhs);
+ }
+ }
+
+ impl RemAssign for Value<$ty> {
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = self.rem(rhs);
+ }
+ }
+ };
+}
+
+impl_float_ops!(F16);
+
+macro_rules! impl_float {
+ ($ty:ident, $bits:ty, $signed_bits:ty) => {
+ impl_float_ops!($ty);
+ impl Float for Value<$ty> {
+ type FloatEncoding = $ty;
+ type BitsType = Value<$bits>;
+ type SignedBitsType = Value<$signed_bits>;
+ fn abs(self) -> Self {
+ #[cfg(feature = "std")]
+ return Value(self.0.abs());
+ #[cfg(not(feature = "std"))]
+ todo!();
+ }
+ fn trunc(self) -> Self {
+ #[cfg(feature = "std")]
+ return Value(self.0.trunc());
+ #[cfg(not(feature = "std"))]
+ todo!();
+ }
+ fn ceil(self) -> Self {
+ #[cfg(feature = "std")]
+ return Value(self.0.ceil());
+ #[cfg(not(feature = "std"))]
+ todo!();
+ }
+ fn floor(self) -> Self {
+ #[cfg(feature = "std")]
+ return Value(self.0.floor());
+ #[cfg(not(feature = "std"))]
+ todo!();
+ }
+ fn round(self) -> Self {
+ #[cfg(feature = "std")]
+ return Value(self.0.round());
+ #[cfg(not(feature = "std"))]
+ todo!();
+ }
+ #[cfg(feature = "fma")]
+ fn fma(self, a: Self, b: Self) -> Self {
+ Value(self.0.mul_add(a.0, b.0))
+ }
+ fn is_nan(self) -> Self::Bool {
+ Value(self.0.is_nan())
+ }
+ fn is_infinite(self) -> Self::Bool {
+ Value(self.0.is_infinite())
+ }
+ fn is_finite(self) -> Self::Bool {
+ Value(self.0.is_finite())
+ }
+ fn from_bits(v: Self::BitsType) -> Self {
+ Value(<$ty>::from_bits(v.0))
+ }
+ fn to_bits(self) -> Self::BitsType {
+ Value(self.0.to_bits())
+ }
+ }
+ };
+}
+
+impl_float!(f32, u32, i32);
+impl_float!(f64, u64, i64);
+
+macro_rules! impl_compare_using_partial_cmp {
+ ($($ty:ty),*) => {
+ $(
+ impl Compare for Value<$ty> {
+ type Bool = Value<bool>;
+ fn eq(self, rhs: Self) -> Self::Bool {
+ Value(self == rhs)
+ }
+ fn ne(self, rhs: Self) -> Self::Bool {
+ Value(self != rhs)
+ }
+ fn lt(self, rhs: Self) -> Self::Bool {
+ Value(self < rhs)
+ }
+ fn gt(self, rhs: Self) -> Self::Bool {
+ Value(self > rhs)
+ }
+ fn le(self, rhs: Self) -> Self::Bool {
+ Value(self <= rhs)
+ }
+ fn ge(self, rhs: Self) -> Self::Bool {
+ Value(self >= rhs)
+ }
+ }
+ )*
+ };
+}
+
+impl_compare_using_partial_cmp![bool, u8, i8, u16, i16, F16, u32, i32, f32, u64, i64, f64];
+
+impl Bool for Value<bool> {}
+
+impl_bit_ops!(bool);
+
+impl<T> Select<Value<T>> for Value<bool> {
+ fn select(self, true_v: Value<T>, false_v: Value<T>) -> Value<T> {
+ if self.0 {
+ true_v
+ } else {
+ false_v
+ }
+ }
+}
+
+macro_rules! impl_from {
+ ($src:ident => [$($dest:ident),*]) => {
+ $(
+ impl From<Value<$src>> for Value<$dest> {
+ fn from(v: Value<$src>) -> Self {
+ Value(v.0.into())
+ }
+ }
+ )*
+ };
+}
+
+impl_from!(u8 => [u16, i16, F16, u32, i32, f32, u64, i64, f64]);
+impl_from!(u16 => [u32, i32, f32, u64, i64, f64]);
+impl_from!(u32 => [u64, i64, f64]);
+impl_from!(i8 => [i16, F16, i32, f32, i64, f64]);
+impl_from!(i16 => [i32, f32, i64, f64]);
+impl_from!(i32 => [i64, f64]);
+impl_from!(F16 => [f32, f64]);
+impl_from!(f32 => [f64]);
+