#[cfg(feature = "simd")]
use crate::V128;
use crate::{F32, F64};
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(not(feature = "simd"), repr(transparent))]
#[cfg_attr(feature = "simd", repr(C))]
pub struct RawVal {
pub(crate) lo64: u64,
#[cfg(feature = "simd")]
pub(crate) hi64: u64,
}
pub trait ReadAs<T> {
fn read_as(&self) -> T;
}
impl ReadAs<RawVal> for RawVal {
fn read_as(&self) -> RawVal {
*self
}
}
macro_rules! impl_read_as_for_int {
( $( $int:ty ),* $(,)? ) => {
$(
impl ReadAs<$int> for RawVal {
fn read_as(&self) -> $int {
self.read_lo64() as $int
}
}
)*
};
}
impl_read_as_for_int!(i8, i16, i32, i64, u8, u16, u32, u64);
macro_rules! impl_read_as_for_float {
( $( $float:ty ),* $(,)? ) => {
$(
impl ReadAs<$float> for RawVal {
fn read_as(&self) -> $float {
<$float>::from_bits(self.read_lo64() as _)
}
}
)*
};
}
impl_read_as_for_float!(f32, f64);
#[cfg(feature = "simd")]
impl ReadAs<V128> for RawVal {
fn read_as(&self) -> V128 {
V128::from(*self)
}
}
impl ReadAs<bool> for RawVal {
fn read_as(&self) -> bool {
self.read_lo64() != 0
}
}
pub trait WriteAs<T> {
fn write_as(&mut self, value: T);
}
impl WriteAs<RawVal> for RawVal {
fn write_as(&mut self, value: RawVal) {
*self = value;
}
}
macro_rules! impl_write_as_for_int {
( $( $int:ty as $as:ty ),* $(,)? ) => {
$(
impl WriteAs<$int> for RawVal {
#[allow(clippy::cast_lossless)]
fn write_as(&mut self, value: $int) {
self.write_lo64(value as $as as _)
}
}
impl WriteAs<::core::num::NonZero<$int>> for RawVal {
fn write_as(&mut self, value: ::core::num::NonZero<$int>) {
<RawVal as WriteAs<$int>>::write_as(self, value.get())
}
}
)*
};
}
impl_write_as_for_int!(i8 as u8, i16 as u16, i32 as u32, i64 as u64);
macro_rules! impl_write_as_for_uint {
( $( $int:ty ),* $(,)? ) => {
$(
impl WriteAs<$int> for RawVal {
#[allow(clippy::cast_lossless)]
fn write_as(&mut self, value: $int) {
self.write_lo64(value as _)
}
}
impl WriteAs<::core::num::NonZero<$int>> for RawVal {
fn write_as(&mut self, value: ::core::num::NonZero<$int>) {
<RawVal as WriteAs<$int>>::write_as(self, value.get())
}
}
)*
};
}
impl_write_as_for_uint!(u8, u16, u32, u64);
impl WriteAs<bool> for RawVal {
#[allow(clippy::cast_lossless)]
fn write_as(&mut self, value: bool) {
self.write_lo64(value as _)
}
}
macro_rules! impl_write_as_for_float {
( $( $float:ty ),* $(,)? ) => {
$(
impl WriteAs<$float> for RawVal {
#[allow(clippy::cast_lossless)]
fn write_as(&mut self, value: $float) {
self.write_lo64(<$float>::to_bits(value) as _)
}
}
)*
};
}
impl_write_as_for_float!(f32, f64);
#[cfg(feature = "simd")]
impl WriteAs<V128> for RawVal {
fn write_as(&mut self, value: V128) {
*self = RawVal::from(value);
}
}
impl RawVal {
fn read_lo64(&self) -> u64 {
self.lo64
}
fn write_lo64(&mut self, bits: u64) {
self.lo64 = bits;
}
pub const fn from_bits64(lo64: u64) -> Self {
Self {
lo64,
#[cfg(feature = "simd")]
hi64: 0,
}
}
pub const fn to_bits64(self) -> u64 {
self.lo64
}
}
macro_rules! impl_from_rawval_for_int {
( $( $int:ty ),* $(,)? ) => {
$(
impl From<RawVal> for $int {
fn from(value: RawVal) -> Self {
value.to_bits64() as _
}
}
)*
};
}
impl_from_rawval_for_int!(i8, i16, i32, i64, u8, u16, u32, u64);
macro_rules! impl_from_rawval_for_float {
( $( $float:ty ),* $(,)? ) => {
$(
impl From<RawVal> for $float {
fn from(value: RawVal) -> Self {
Self::from_bits(value.to_bits64() as _)
}
}
)*
};
}
impl_from_rawval_for_float!(f32, f64, F32, F64);
#[cfg(feature = "simd")]
impl From<RawVal> for V128 {
fn from(value: RawVal) -> Self {
let u128 = (u128::from(value.hi64) << 64) | (u128::from(value.lo64));
Self::from(u128)
}
}
#[cfg(feature = "simd")]
impl From<V128> for RawVal {
fn from(value: V128) -> Self {
let u128 = value.as_u128();
let lo64 = u128 as u64;
let hi64 = (u128 >> 64) as u64;
Self { lo64, hi64 }
}
}
impl From<RawVal> for bool {
fn from(value: RawVal) -> Self {
value.to_bits64() != 0
}
}
macro_rules! impl_from_unsigned_prim {
( $( $prim:ty ),* $(,)? ) => {
$(
impl From<$prim> for RawVal {
#[allow(clippy::cast_lossless)]
fn from(value: $prim) -> Self {
Self::from_bits64(value as _)
}
}
impl From<::core::num::NonZero<$prim>> for RawVal {
fn from(value: ::core::num::NonZero<$prim>) -> Self {
<_ as From<$prim>>::from(value.get())
}
}
)*
};
}
#[rustfmt::skip]
impl_from_unsigned_prim!(
u8, u16, u32, u64,
);
impl From<bool> for RawVal {
#[allow(clippy::cast_lossless)]
fn from(value: bool) -> Self {
Self::from_bits64(value as _)
}
}
macro_rules! impl_from_signed_prim {
( $( $prim:ty as $base:ty ),* $(,)? ) => {
$(
impl From<$prim> for RawVal {
#[allow(clippy::cast_lossless)]
fn from(value: $prim) -> Self {
Self::from_bits64(u64::from(value as $base))
}
}
impl From<::core::num::NonZero<$prim>> for RawVal {
fn from(value: ::core::num::NonZero<$prim>) -> Self {
<_ as From<$prim>>::from(value.get())
}
}
)*
};
}
#[rustfmt::skip]
impl_from_signed_prim!(
i8 as u8,
i16 as u16,
i32 as u32,
i64 as u64,
);
macro_rules! impl_from_float {
( $( $float:ty ),* $(,)? ) => {
$(
impl From<$float> for RawVal {
fn from(value: $float) -> Self {
Self::from_bits64(u64::from(value.to_bits()))
}
}
)*
};
}
impl_from_float!(f32, f64, F32, F64);