pub trait SafeConvert<T>: Sized {
fn checked_convert(self) -> Option<T>;
fn saturating_convert(self) -> T;
fn wrapping_convert(self) -> T;
}
macro_rules! impl_safe_convert {
($src:ty => $($dst:ty),*) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
<$dst>::try_from(self).ok()
}
fn saturating_convert(self) -> $dst {
if let Ok(v) = <$dst>::try_from(self) {
v
} else if self < 0 {
0
} else {
<$dst>::MAX
}
}
fn wrapping_convert(self) -> $dst {
self as $dst
}
}
)*
};
}
macro_rules! impl_safe_unsigned_convert {
($src:ty => $($dst:ty),*) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
<$dst>::try_from(self).ok()
}
fn saturating_convert(self) -> $dst {
if self > <$dst>::MAX as $src {
<$dst>::MAX
}else{
self as $dst
}
}
fn wrapping_convert(self) -> $dst {
self as $dst
}
}
)*
};
}
macro_rules! impl_safe_convert_signed_to_float {
($mantissa_bits:expr; $src:ty => $($float:ty),* $(,)?) => {
$(
impl SafeConvert<$float> for $src {
fn checked_convert(self) -> Option<$float> {
let val = self as i128;
let max_exact = 1i128 << $mantissa_bits;
if val >= -max_exact && val <= max_exact {
Some(self as $float)
} else {
None
}
}
fn saturating_convert(self) -> $float {
let max_exact = 1i128 << $mantissa_bits;
let min = -max_exact;
let max = max_exact;
let val = self as i128;
if val < min {
min as $float
} else if val > max {
max as $float
} else {
self as $float
}
}
fn wrapping_convert(self) -> $float {
self as $float
}
}
)*
};
}
macro_rules! impl_safe_convert_unsigned_to_float {
($mantissa_bits:expr; $src:ty => $($float:ty),* $(,)?) => {
$(
impl SafeConvert<$float> for $src {
fn checked_convert(self) -> Option<$float> {
if self as u64 <= (1u64 << $mantissa_bits) {
Some(self as $float)
} else {
None
}
}
fn saturating_convert(self) -> $float {
let max_exact = 1u64 << $mantissa_bits;
let max = max_exact as u128;
let val = self as u128;
if val > max {
max as $float
} else {
self as $float
}
}
fn wrapping_convert(self) -> $float {
self as $float
}
}
)*
};
}
macro_rules! impl_safe_convert_float_to_signed {
($src:ty => $($dst:ty),* $(,)?) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
if self.is_nan() || self.is_infinite() {
return None;
}
let min_val = <$dst>::MIN as $src;
let max_val = <$dst>::MAX as $src;
if self < min_val || self > max_val {
None
} else {
Some(self as $dst)
}
}
fn saturating_convert(self) -> $dst {
if self.is_nan() {
return 0;
}
if self.is_infinite() {
return if self.is_sign_positive() { <$dst>::MAX } else { <$dst>::MIN };
}
let min_val = <$dst>::MIN as $src;
let max_val = <$dst>::MAX as $src;
if self < min_val {
<$dst>::MIN
} else if self > max_val {
<$dst>::MAX
} else {
self as $dst
}
}
fn wrapping_convert(self) -> $dst {
if self.is_nan() {
return 0;
}
if self.is_infinite() {
return if self.is_sign_positive() { <$dst>::MAX } else { <$dst>::MIN };
}
self as $dst
}
}
)*
};
}
macro_rules! impl_safe_convert_float_to_unsigned {
($src:ty => $($dst:ty),* $(,)?) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
if self.is_nan() || self.is_infinite() || self < 0.0 {
return None;
}
let max_val = <$dst>::MAX as $src;
if self > max_val {
None
} else {
Some(self as $dst)
}
}
fn saturating_convert(self) -> $dst {
if self.is_nan() || self < 0.0 {
return 0;
}
if self.is_infinite() {
return <$dst>::MAX;
}
let max_val = <$dst>::MAX as $src;
if self > max_val {
<$dst>::MAX
} else {
self as $dst
}
}
fn wrapping_convert(self) -> $dst {
if self.is_nan() || self < 0.0 {
return 0;
}
if self.is_infinite() {
return <$dst>::MAX;
}
self as $dst
}
}
)*
};
}
use arrow_buffer::i256;
use crate::value::decimal::Decimal;
fn narrow_i256<T: TryFrom<i128> + TryFrom<u128>>(value: i256) -> Option<T> {
match value.to_i128() {
Some(value) => T::try_from(value).ok(),
None => match value.to_parts() {
(low, 0) => T::try_from(low).ok(),
_ => None,
},
}
}
macro_rules! impl_safe_convert_promote {
($src:ty => $($dst:ty),* $(,)?) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
Some(self as $dst)
}
fn saturating_convert(self) -> $dst {
self as $dst
}
fn wrapping_convert(self) -> $dst {
self as $dst
}
}
)*
};
}
macro_rules! impl_safe_convert_demote {
($src:ty => $($dst:ty),* $(,)?) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
<$dst>::try_from(self).ok()
}
fn saturating_convert(self) -> $dst {
match <$dst>::try_from(self) {
Ok(v) => v,
Err(_) => {
if self < <$dst>::MIN as $src {
<$dst>::MIN
} else {
<$dst>::MAX
}
}
}
}
fn wrapping_convert(self) -> $dst {
self as $dst
}
}
)*
};
}
macro_rules! impl_safe_convert_unsigned_demote {
($src:ty => $($dst:ty),* $(,)?) => {
$(
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
<$dst>::try_from(self).ok()
}
fn saturating_convert(self) -> $dst {
if self > <$dst>::MAX as $src {
<$dst>::MAX
} else {
self as $dst
}
}
fn wrapping_convert(self) -> $dst {
self as $dst
}
}
)*
};
}
macro_rules! impl_safe_convert_float_demote {
($src:ty => $dst:ty) => {
impl SafeConvert<$dst> for $src {
fn checked_convert(self) -> Option<$dst> {
let demoted = self as $dst;
if self.is_finite() && demoted.is_finite() {
Some(demoted)
} else {
None
}
}
fn saturating_convert(self) -> $dst {
if self.is_nan() {
<$dst>::NAN
} else if self <= <$dst>::MIN as $src {
<$dst>::MIN
} else if self >= <$dst>::MAX as $src {
<$dst>::MAX
} else {
self as $dst
}
}
fn wrapping_convert(self) -> $dst {
self as $dst
}
}
};
}
macro_rules! impl_safe_convert_self {
($($ty:ty),* $(,)?) => {
$(
impl SafeConvert<$ty> for $ty {
fn checked_convert(self) -> Option<$ty> {
Some(self)
}
fn saturating_convert(self) -> $ty {
self
}
fn wrapping_convert(self) -> $ty {
self
}
}
)*
};
}
macro_rules! impl_safe_convert_to_decimal_from_int {
($($src:ty),* $(,)?) => {
$(
impl SafeConvert<Decimal> for $src {
fn checked_convert(self) -> Option<Decimal> {
Some(Decimal::from(self))
}
fn saturating_convert(self) -> Decimal {
Decimal::from(self)
}
fn wrapping_convert(self) -> Decimal {
Decimal::from(self)
}
}
)*
};
}
macro_rules! impl_safe_convert_to_decimal_from_large_int {
($($src:ty),* $(,)?) => {
$(
impl SafeConvert<Decimal> for $src {
fn checked_convert(self) -> Option<Decimal> {
Some(Decimal::from(self))
}
fn saturating_convert(self) -> Decimal {
Decimal::from(self)
}
fn wrapping_convert(self) -> Decimal {
Decimal::from(self)
}
}
)*
};
}
macro_rules! impl_safe_convert_to_decimal_from_uint {
($($src:ty),* $(,)?) => {
$(
impl SafeConvert<Decimal> for $src {
fn checked_convert(self) -> Option<Decimal> {
Some(Decimal::from(self))
}
fn saturating_convert(self) -> Decimal {
Decimal::from(self)
}
fn wrapping_convert(self) -> Decimal {
Decimal::from(self)
}
}
)*
};
}
macro_rules! impl_safe_convert_to_decimal_from_float {
($($src:ty => $from:ident),* $(,)?) => {
$(
impl SafeConvert<Decimal> for $src {
fn checked_convert(self) -> Option<Decimal> {
Decimal::$from(self)
}
fn saturating_convert(self) -> Decimal {
Decimal::from(self)
}
fn wrapping_convert(self) -> Decimal {
Decimal::from(self)
}
}
)*
};
}
impl_safe_convert_self!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64);
impl_safe_convert_self!(Decimal);
pub mod decimal;
pub mod f32;
pub mod f64;
pub mod i128;
pub mod i16;
pub mod i32;
pub mod i64;
pub mod i8;
pub mod u128;
pub mod u16;
pub mod u32;
pub mod u64;
pub mod u8;