use crate::var_num::ParseError;
use crate::{VarInt, VarUInt};
use derive_more::{Display, Neg};
use std::fmt;
use std::fmt::Binary;
use std::hash::{Hash, Hasher};
use std::ops::{BitAnd, BitOr, BitXor, Not, Rem, Shl, Shr};
use std::str::FromStr;
#[derive(Copy, Clone, Debug, Display, PartialEq, Neg, PartialOrd)]
pub enum VarFloat {
F32(f32),
F64(f64),
}
impl Hash for VarFloat {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
VarFloat::F32(f) => state.write_u32(f.to_bits()),
VarFloat::F64(f) => state.write_u64(f.to_bits())
}
}
}
impl Eq for VarFloat {
}
impl FromStr for VarFloat {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let f: f64 = match s.parse() {
Ok(f) => f,
Err(e) => return Err(ParseError::InvalidNumber(format!("Invalid Float: {}", e))),
};
Ok(f.into())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for VarFloat {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
VarFloat::F32(v) => serializer.serialize_f32(*v),
VarFloat::F64(v) => serializer.serialize_f64(*v),
}
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for VarFloat {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(f64::deserialize(deserializer)?.into())
}
}
impl VarFloat {
#[inline]
pub fn reverse(&self) -> Self {
match self {
VarFloat::F32(f) => {
VarFloat::F32(f32::from_bits(f.to_bits().reverse_bits()))
}
VarFloat::F64(f) => {
VarFloat::F64(f64::from_bits(f.to_bits().reverse_bits()))
}
}
}
#[inline]
pub fn zero() -> Self {
VarFloat::F32(0.0)
}
#[inline]
pub fn one() -> Self {
VarFloat::F32(1.0)
}
#[inline]
pub fn is_non_zero(&self) -> bool {
match self {
VarFloat::F32(f) => *f != 0.0,
VarFloat::F64(f) => *f != 0.0
}
}
#[inline]
pub fn is_zero(&self) -> bool {
match self {
VarFloat::F32(f) => *f == 0.0,
VarFloat::F64(f) => *f == 0.0
}
}
#[inline]
pub fn is_one(&self) -> bool {
match self {
VarFloat::F32(f) => *f == 1.0,
VarFloat::F64(f) => *f == 1.0
}
}
#[inline]
pub fn to_int(&self) -> VarInt {
match self {
VarFloat::F32(v) => (*v as i32).into(),
VarFloat::F64(v) => (*v as i64).into(),
}
}
#[inline]
pub fn to_uint(&self) -> VarUInt {
match self {
VarFloat::F32(v) => (*v as u32).into(),
VarFloat::F64(v) => (*v as u64).into(),
}
}
#[inline]
pub fn upgrade(&self) -> Self {
match self {
Self::F32(v) => Self::F64(*v as f64),
Self::F64(v) => panic!("cannot upgrade f64 value: {}", v),
}
}
#[inline]
pub fn downgrade(&self) -> Self {
match self {
Self::F32(v) => panic!("cannot downgrade f32 value: {}", v),
Self::F64(v) => Self::F32(*v as f32),
}
}
#[inline]
pub fn to_bytes(&self) -> Vec<u8> {
match self {
Self::F32(v) => v.to_be_bytes().to_vec(),
Self::F64(v) => v.to_be_bytes().to_vec(),
}
}
#[inline]
pub fn from_bytes(raw: Vec<u8>) -> Self {
match raw.len() {
4 => {
let mut bytes = [0; 4];
bytes.copy_from_slice(&raw);
Self::F32(f32::from_be_bytes(bytes))
}
8 => {
let mut bytes = [0; 8];
bytes.copy_from_slice(&raw);
Self::F64(f64::from_be_bytes(bytes))
}
_ => panic!("invalid byte length: {}", raw.len()),
}
}
pub fn normalize(lhs: Self, rhs: Self) -> (Self, Self) {
match (lhs, rhs) {
(Self::F32(lhs), Self::F32(rhs)) => (Self::F32(lhs), Self::F32(rhs)),
(Self::F32(lhs), rhs) => Self::normalize(Self::F32(lhs).upgrade(), rhs),
(lhs, Self::F32(rhs)) => Self::normalize(lhs, Self::F32(rhs).upgrade()),
(Self::F64(lhs), Self::F64(rhs)) => (Self::F64(lhs), Self::F64(rhs)),
}
}
}
impl Binary for VarFloat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VarFloat::F32(v) => fmt::Binary::fmt(&(v.to_bits()), f),
VarFloat::F64(v) => fmt::Binary::fmt(&(v.to_bits()), f),
}
}
}
impl Rem for VarFloat {
type Output = VarFloat;
fn rem(self, rhs: Self) -> Self::Output {
let (lhs, rhs) = VarFloat::normalize(self, rhs);
match (lhs, rhs) {
(VarFloat::F32(lhs), VarFloat::F32(rhs)) => ((lhs as u32) % (rhs as u32)).into(),
(VarFloat::F64(lhs), VarFloat::F64(rhs)) => ((lhs as u64) % (rhs as u64)).into(),
(lhs, rhs) => panic!("normalization failed: {} % {}", lhs, rhs),
}
}
}
macro_rules! impl_bin_var_float_to_bits {
($($trait:ident: $method:ident($op:tt),)*) => {
$(
impl $trait for VarFloat {
type Output = VarFloat;
fn $method(self, rhs: Self) -> Self::Output {
match VarFloat::normalize(self, rhs) {
(VarFloat::F32(lhs), VarFloat::F32(rhs)) => VarFloat::F32(f32::from_bits(lhs.to_bits() $op rhs.to_bits())),
(VarFloat::F64(lhs), VarFloat::F64(rhs)) => VarFloat::F64(f64::from_bits(lhs.to_bits() $op rhs.to_bits())),
(lhs, rhs) => panic!("normalization failed: {} {} {}", lhs, stringify!($op), rhs),
}
}
}
)*
};
}
impl_bin_var_float_to_bits! {
BitAnd: bitand(&),
BitOr: bitor(|),
BitXor: bitxor(^),
Shl: shl(<<),
Shr: shr(>>),
}
impl Not for VarFloat {
type Output = VarFloat;
fn not(self) -> Self::Output {
match self {
VarFloat::F32(v) => (!(v as u32)).into(),
VarFloat::F64(v) => (!(v as u64)).into(),
}
}
}
macro_rules! from_primitive_var_float {
($($type:ty)*) => {
$(
impl From<$type> for VarFloat {
fn from(value: $type) -> Self {
VarFloat::F32(value as f32)
}
}
)*
};
}
macro_rules! from_primitive_var_float64 {
($($type:ty)*) => {
$(
impl From<$type> for VarFloat {
fn from(value: $type) -> Self {
if value <= f32::MAX as $type {
VarFloat::F32(value as f32)
} else {
VarFloat::F64(value as f64)
}
}
}
)*
};
}
from_primitive_var_float! { f32 u8 u16 u32 i8 i16 i32 }
from_primitive_var_float64! { f64 u64 i64 usize isize }