use crate::ns::*;
use num_traits::FromPrimitive;
use std::ops::{BitXor, BitOr};
#[derive(Clone, PartialEq)]
pub enum NumberVariant {
Number(f64),
Float(f32),
Int(i32),
Uint(u32),
}
impl BitXor for NumberVariant {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
match self {
Self::Float(v) => {
let Self::Float(rhs) = rhs else { panic!(); };
Self::Float(f32::from_u32(unsafe { v.to_int_unchecked::<u32>() } ^ unsafe { rhs.to_int_unchecked::<u32>() }).unwrap_or(0.0))
},
Self::Number(v) => {
let Self::Number(rhs) = rhs else { panic!(); };
Self::Number(f64::from_u32(unsafe { v.to_int_unchecked::<u32>() } ^ unsafe { rhs.to_int_unchecked::<u32>() }).unwrap_or(0.0))
},
Self::Int(v) => {
let Self::Int(rhs) = rhs else { panic!(); };
Self::Int(v ^ rhs)
},
Self::Uint(v) => {
let Self::Uint(rhs) = rhs else { panic!(); };
Self::Uint(v ^ rhs)
},
}
}
}
impl BitOr for NumberVariant {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
match self {
Self::Float(v) => {
let Self::Float(rhs) = rhs else { panic!(); };
Self::Float(f32::from_u32(unsafe { v.to_int_unchecked::<u32>() } | unsafe { rhs.to_int_unchecked::<u32>() }).unwrap_or(0.0))
},
Self::Number(v) => {
let Self::Number(rhs) = rhs else { panic!(); };
Self::Number(f64::from_u32(unsafe { v.to_int_unchecked::<u32>() } | unsafe { rhs.to_int_unchecked::<u32>() }).unwrap_or(0.0))
},
Self::Int(v) => {
let Self::Int(rhs) = rhs else { panic!(); };
Self::Int(v | rhs)
},
Self::Uint(v) => {
let Self::Uint(rhs) = rhs else { panic!(); };
Self::Uint(v | rhs)
},
}
}
}
impl NumberVariant {
pub fn zero(type_thing: &Thingy, host: &SemanticHost) -> Self {
if type_thing == &host.number_type() {
Self::Number(0.0)
} else if type_thing == &host.int_type() {
Self::Int(0)
} else if type_thing == &host.uint_type() {
Self::Uint(0)
} else if type_thing == &host.float_type() {
Self::Float(0.0)
} else {
panic!()
}
}
pub fn nan(type_thing: &Thingy, host: &SemanticHost) -> Self {
if type_thing == &host.number_type() {
Self::Number(f64::NAN)
} else if type_thing == &host.float_type() {
Self::Float(f32::NAN)
} else {
panic!("Type does not support NaN.");
}
}
pub fn one(type_thing: &Thingy, host: &SemanticHost) -> Self {
if type_thing == &host.number_type() {
Self::Number(1.0)
} else if type_thing == &host.int_type() {
Self::Int(1)
} else if type_thing == &host.uint_type() {
Self::Uint(1)
} else if type_thing == &host.float_type() {
Self::Float(1.0)
} else {
panic!()
}
}
pub fn minimum_value(type_thing: &Thingy, host: &SemanticHost) -> Self {
if type_thing == &host.number_type() {
Self::Number(f64::NEG_INFINITY)
} else if type_thing == &host.int_type() {
Self::Int(i32::MIN)
} else if type_thing == &host.uint_type() {
Self::Uint(0)
} else if type_thing == &host.float_type() {
Self::Float(f32::NEG_INFINITY)
} else {
panic!()
}
}
pub fn maximum_value(type_thing: &Thingy, host: &SemanticHost) -> Self {
if type_thing == &host.number_type() {
Self::Number(f64::INFINITY)
} else if type_thing == &host.int_type() {
Self::Int(i32::MAX)
} else if type_thing == &host.uint_type() {
Self::Uint(u32::MAX)
} else if type_thing == &host.float_type() {
Self::Float(f32::INFINITY)
} else {
panic!()
}
}
pub fn is_zero(&self) -> bool {
match self {
Self::Float(v) => v == &0.0,
Self::Number(v) => v == &0.0,
Self::Int(v) => v == &0,
Self::Uint(v) => v == &0,
}
}
pub fn is_one(&self) -> bool {
match self {
Self::Float(v) => v == &1.0,
Self::Number(v) => v == &1.0,
Self::Int(v) => v == &1,
Self::Uint(v) => v == &1,
}
}
pub fn multiply_per_two(&self) -> Self {
match self {
Self::Float(v) => Self::Float(v * 2.0),
Self::Number(v) => Self::Number(v * 2.0),
Self::Int(v) => Self::Int(v * 2),
Self::Uint(v) => Self::Uint(v * 2),
}
}
pub fn increase_by_one(&self) -> Self {
match self {
Self::Float(v) => Self::Float(v + 1.0),
Self::Number(v) => Self::Number(v + 1.0),
Self::Int(v) => Self::Int(v + 1),
Self::Uint(v) => Self::Uint(v + 1),
}
}
pub fn apply_bits(&self, bits: &Self, value: bool) -> Self {
if value { self.clone() | bits.clone() } else { self.erase_bits(bits) }
}
pub fn erase_bits(&self, bits: &Self) -> Self {
if self.includes_bits(bits) { self.clone() ^ bits.clone() } else { self.clone() }
}
pub fn includes_bits(&self, rhs: &Self) -> bool {
match self {
Self::Float(v) => {
let Self::Float(rhs) = rhs else { panic!(); };
(unsafe { v.to_int_unchecked::<u32>() } & unsafe { rhs.to_int_unchecked::<u32>() } != 0)
},
Self::Number(v) => {
let Self::Number(rhs) = rhs else { panic!(); };
(unsafe { v.to_int_unchecked::<u32>() } & unsafe { rhs.to_int_unchecked::<u32>() } != 0)
},
Self::Int(v) => {
let Self::Int(rhs) = rhs else { panic!(); };
v & rhs != 0
},
Self::Uint(v) => {
let Self::Uint(rhs) = rhs else { panic!(); };
v & rhs != 0
},
}
}
pub fn is_power_of_two(&self) -> bool {
match self {
Self::Float(v) => {
let v = unsafe { v.to_int_unchecked::<u32>() };
(v != 0) && ((v & (v - 1)) == 0)
},
Self::Number(v) => {
let v = unsafe { v.to_int_unchecked::<u32>() };
(v != 0) && ((v & (v - 1)) == 0)
},
Self::Int(v) => (v != &0) && ((v & (v - 1)) == 0),
Self::Uint(v) => (v != &0) && ((v & (v - 1)) == 0),
}
}
pub fn convert_type(&self, target_type: &Thingy, host: &SemanticHost) -> Result<Self, DeferError> {
let number_type = host.number_type().defer()?;
let float_type = host.float_type().defer()?;
let int_type = host.int_type().defer()?;
let uint_type = host.int_type().defer()?;
Ok(if target_type == &number_type {
match self {
Self::Float(v) => Self::Number(*v as f64),
Self::Number(v) => Self::Number(*v),
Self::Int(v) => {
let v: Result<i32, _> = (*v).try_into();
Self::Number(v.map(|v| v as f64).unwrap_or(f64::NAN))
},
Self::Uint(v) => {
let v: Result<u32, _> = (*v).try_into();
Self::Number(v.map(|v| v as f64).unwrap_or(f64::NAN))
},
}
} else if target_type == &float_type {
match self {
Self::Float(v) => Self::Float(*v),
Self::Number(v) => Self::Float(*v as f32),
Self::Int(v) => {
let v: Result<i32, _> = (*v).try_into();
Self::Float(v.map(|v| v as f32).unwrap_or(f32::NAN))
},
Self::Uint(v) => {
let v: Result<u32, _> = (*v).try_into();
Self::Float(v.map(|v| v as f32).unwrap_or(f32::NAN))
},
}
} else if target_type == &int_type {
match self {
Self::Float(v) => Self::Int(if v.is_infinite() {
if v.is_sign_negative() { i32::MIN } else { i32::MAX }
} else if v.is_nan() { 0 } else { unsafe { v.to_int_unchecked() } }),
Self::Number(v) => Self::Int(if v.is_infinite() {
if v.is_sign_negative() { i32::MIN } else { i32::MAX }
} else if v.is_nan() { 0 } else { unsafe { v.to_int_unchecked() } }),
Self::Int(v) => Self::Int((*v).try_into().unwrap_or(0)),
Self::Uint(v) => Self::Int((*v).try_into().unwrap_or(0)),
}
} else if target_type == &uint_type {
match self {
Self::Float(v) => Self::Uint(if v.is_infinite() {
if v.is_sign_negative() { u32::MIN } else { u32::MAX }
} else if v.is_nan() { 0 } else { unsafe { v.to_int_unchecked() } }),
Self::Number(v) => Self::Uint(if v.is_infinite() {
if v.is_sign_negative() { u32::MIN } else { u32::MAX }
} else if v.is_nan() { 0 } else { unsafe { v.to_int_unchecked() } }),
Self::Int(v) => Self::Uint((*v).try_into().unwrap_or(0)),
Self::Uint(v) => Self::Uint((*v).try_into().unwrap_or(0)),
}
} else {
panic!()
})
}
pub fn is_nan(&self) -> bool {
match self {
Self::Number(f) => f.is_nan(),
Self::Float(f) => f.is_nan(),
_ => false,
}
}
pub fn is_negative_infinity(&self) -> bool {
match self {
Self::Number(f) => f == &f64::NEG_INFINITY,
Self::Float(f) => f == &f32::NEG_INFINITY,
_ => false,
}
}
pub fn is_positive_infinity(&self) -> bool {
match self {
Self::Number(f) => f == &f64::INFINITY,
Self::Float(f) => f == &f32::INFINITY,
_ => false,
}
}
pub fn as_double(&self) -> Option<f64> {
if let NumberVariant::Number(v) = self { Some(*v) } else { None }
}
pub fn as_float(&self) -> Option<f32> {
if let NumberVariant::Float(v) = self { Some(*v) } else { None }
}
pub fn as_int(&self) -> Option<i32> {
if let NumberVariant::Int(v) = self { Some(*v) } else { None }
}
pub fn as_uint(&self) -> Option<u32> {
if let NumberVariant::Uint(v) = self { Some(*v) } else { None }
}
}