+use crate::{
+ f16::F16,
+ traits::{ConvertFrom, ConvertTo},
+};
+use core::{fmt, hash, ops};
+
+mod sealed {
+ use crate::f16::F16;
+
+ pub trait Sealed {}
+ impl Sealed for F16 {}
+ impl Sealed for f32 {}
+ impl Sealed for f64 {}
+ impl Sealed for u8 {}
+ impl Sealed for u16 {}
+ impl Sealed for u32 {}
+ impl Sealed for u64 {}
+ impl Sealed for i8 {}
+ impl Sealed for i16 {}
+ impl Sealed for i32 {}
+ impl Sealed for i64 {}
+}
+
+pub trait PrimBase:
+ sealed::Sealed
+ + Copy
+ + 'static
+ + Send
+ + Sync
+ + PartialOrd
+ + fmt::Debug
+ + fmt::Display
+ + ops::Add<Output = Self>
+ + ops::Sub<Output = Self>
+ + ops::Mul<Output = Self>
+ + ops::Div<Output = Self>
+ + ops::Rem<Output = Self>
+ + ops::AddAssign
+ + ops::SubAssign
+ + ops::MulAssign
+ + ops::DivAssign
+ + ops::RemAssign
+ + ConvertFrom<i8>
+ + ConvertFrom<u8>
+ + ConvertFrom<i16>
+ + ConvertFrom<u16>
+ + ConvertFrom<F16>
+ + ConvertFrom<i32>
+ + ConvertFrom<u32>
+ + ConvertFrom<f32>
+ + ConvertFrom<i64>
+ + ConvertFrom<u64>
+ + ConvertFrom<f64>
+ + ConvertTo<i8>
+ + ConvertTo<u8>
+ + ConvertTo<i16>
+ + ConvertTo<u16>
+ + ConvertTo<F16>
+ + ConvertTo<i32>
+ + ConvertTo<u32>
+ + ConvertTo<f32>
+ + ConvertTo<i64>
+ + ConvertTo<u64>
+ + ConvertTo<f64>
+{
+}
+
+pub trait PrimInt:
+ PrimBase
+ + Ord
+ + hash::Hash
+ + fmt::Binary
+ + fmt::LowerHex
+ + fmt::Octal
+ + fmt::UpperHex
+ + ops::BitAnd<Output = Self>
+ + ops::BitOr<Output = Self>
+ + ops::BitXor<Output = Self>
+ + ops::Shl<Output = Self>
+ + ops::Shr<Output = Self>
+ + ops::Not<Output = Self>
+ + ops::BitAndAssign
+ + ops::BitOrAssign
+ + ops::BitXorAssign
+ + ops::ShlAssign
+ + ops::ShrAssign
+{
+}
+
+pub trait PrimUInt: PrimInt + ConvertFrom<Self::SignedType> {
+ type SignedType: PrimSInt<UnsignedType = Self> + ConvertFrom<Self>;
+}
+
+pub trait PrimSInt: PrimInt + ops::Neg<Output = Self> + ConvertFrom<Self::UnsignedType> {
+ type UnsignedType: PrimUInt<SignedType = Self> + ConvertFrom<Self>;
+}
+
+macro_rules! impl_int {
+ ($uint:ident, $sint:ident) => {
+ impl PrimBase for $uint {}
+ impl PrimBase for $sint {}
+ impl PrimInt for $uint {}
+ impl PrimInt for $sint {}
+ impl PrimUInt for $uint {
+ type SignedType = $sint;
+ }
+ impl PrimSInt for $sint {
+ type UnsignedType = $uint;
+ }
+ };
+}
+
+impl_int!(u8, i8);
+impl_int!(u16, i16);
+impl_int!(u32, i32);
+impl_int!(u64, i64);
+
+pub trait PrimFloat:
+ PrimBase + ops::Neg<Output = Self> + ConvertFrom<Self::BitsType> + ConvertFrom<Self::SignedBitsType>
+{
+ type BitsType: PrimUInt<SignedType = Self::SignedBitsType> + ConvertFrom<Self>;
+ type SignedBitsType: PrimSInt<UnsignedType = Self::BitsType> + ConvertFrom<Self>;
+ const EXPONENT_BIAS_UNSIGNED: Self::BitsType;
+ const EXPONENT_BIAS_SIGNED: Self::SignedBitsType;
+ const SIGN_FIELD_WIDTH: Self::BitsType;
+ const EXPONENT_FIELD_WIDTH: Self::BitsType;
+ const MANTISSA_FIELD_WIDTH: Self::BitsType;
+ const SIGN_FIELD_SHIFT: Self::BitsType;
+ const EXPONENT_FIELD_SHIFT: Self::BitsType;
+ const MANTISSA_FIELD_SHIFT: Self::BitsType;
+ const SIGN_FIELD_MASK: Self::BitsType;
+ const EXPONENT_FIELD_MASK: Self::BitsType;
+ const MANTISSA_FIELD_MASK: Self::BitsType;
+ const IMPLICIT_MANTISSA_BIT: Self::BitsType;
+ const ZERO_SUBNORMAL_EXPONENT: Self::BitsType;
+ const NAN_INFINITY_EXPONENT: Self::BitsType;
+ const INFINITY_BITS: Self::BitsType;
+ const NAN_BITS: Self::BitsType;
+}
+
+macro_rules! impl_float {
+ (
+ impl PrimFloat for $float:ident {
+ type BitsType = $bits_type:ident;
+ type SignedBitsType = $signed_bits_type:ident;
+ const EXPONENT_FIELD_WIDTH: u32 = $exponent_field_width:literal;
+ const MANTISSA_FIELD_WIDTH: u32 = $mantissa_field_width:literal;
+ }
+ ) => {
+ impl PrimBase for $float {}
+
+ impl PrimFloat for $float {
+ type BitsType = $bits_type;
+ type SignedBitsType = $signed_bits_type;
+ const EXPONENT_BIAS_UNSIGNED: Self::BitsType =
+ (1 << (Self::EXPONENT_FIELD_WIDTH - 1)) - 1;
+ const EXPONENT_BIAS_SIGNED: Self::SignedBitsType = Self::EXPONENT_BIAS_UNSIGNED as _;
+ const SIGN_FIELD_WIDTH: Self::BitsType = 1;
+ const EXPONENT_FIELD_WIDTH: Self::BitsType = $exponent_field_width;
+ const MANTISSA_FIELD_WIDTH: Self::BitsType = $mantissa_field_width;
+ const SIGN_FIELD_SHIFT: Self::BitsType =
+ Self::EXPONENT_FIELD_SHIFT + Self::EXPONENT_FIELD_WIDTH;
+ const EXPONENT_FIELD_SHIFT: Self::BitsType = Self::MANTISSA_FIELD_WIDTH;
+ const MANTISSA_FIELD_SHIFT: Self::BitsType = 0;
+ const SIGN_FIELD_MASK: Self::BitsType = 1 << Self::SIGN_FIELD_SHIFT;
+ const EXPONENT_FIELD_MASK: Self::BitsType =
+ ((1 << Self::EXPONENT_FIELD_WIDTH) - 1) << Self::EXPONENT_FIELD_SHIFT;
+ const MANTISSA_FIELD_MASK: Self::BitsType = (1 << Self::MANTISSA_FIELD_WIDTH) - 1;
+ const IMPLICIT_MANTISSA_BIT: Self::BitsType = 1 << Self::MANTISSA_FIELD_WIDTH;
+ const ZERO_SUBNORMAL_EXPONENT: Self::BitsType = 0;
+ const NAN_INFINITY_EXPONENT: Self::BitsType = (1 << Self::EXPONENT_FIELD_WIDTH) - 1;
+ const INFINITY_BITS: Self::BitsType =
+ Self::NAN_INFINITY_EXPONENT << Self::EXPONENT_FIELD_SHIFT;
+ const NAN_BITS: Self::BitsType =
+ Self::INFINITY_BITS | (1 << (Self::MANTISSA_FIELD_WIDTH - 1));
+ }
+ };
+}
+
+impl_float! {
+ impl PrimFloat for F16 {
+ type BitsType = u16;
+ type SignedBitsType = i16;
+ const EXPONENT_FIELD_WIDTH: u32 = 5;
+ const MANTISSA_FIELD_WIDTH: u32 = 10;
+ }
+}
+
+impl_float! {
+ impl PrimFloat for f32 {
+ type BitsType = u32;
+ type SignedBitsType = i32;
+ const EXPONENT_FIELD_WIDTH: u32 = 8;
+ const MANTISSA_FIELD_WIDTH: u32 = 23;
+ }
+}
+
+impl_float! {
+ impl PrimFloat for f64 {
+ type BitsType = u64;
+ type SignedBitsType = i64;
+ const EXPONENT_FIELD_WIDTH: u32 = 11;
+ const MANTISSA_FIELD_WIDTH: u32 = 52;
+ }
+}