use rust_decimal::prelude::*;
use super::Byte;
use crate::{common::is_zero_remainder_decimal, Unit};
const DECIMAL_EIGHT: Decimal = Decimal::from_parts(8, 0, 0, false, 0);
impl Byte {
#[inline]
pub fn from_decimal(size: Decimal) -> Option<Self> {
if size >= Decimal::ZERO {
#[cfg(feature = "u128")]
{
let size = size.ceil();
match size.to_u128() {
Some(n) => Self::from_u128(n),
None => None,
}
}
#[cfg(not(feature = "u128"))]
{
let size = size.ceil();
size.to_u64().map(Self::from_u64)
}
} else {
None
}
}
}
impl Byte {
#[inline]
pub fn from_decimal_with_unit(size: Decimal, unit: Unit) -> Option<Self> {
let v = {
match unit {
Unit::Bit => (size / DECIMAL_EIGHT).ceil(),
Unit::B => size,
_ => size.checked_mul(Decimal::from(unit.as_bytes_u128()))?,
}
};
Self::from_decimal(v)
}
}
impl Byte {
#[inline]
pub fn get_recoverable_unit(
self,
allow_in_bits: bool,
mut precision: usize,
) -> (Decimal, Unit) {
let bytes_v = self.as_u128();
let bytes_vd = Decimal::from(bytes_v);
let a = if allow_in_bits { Unit::get_multiples() } else { Unit::get_multiples_bytes() };
let mut i = a.len() - 1;
if precision >= 28 {
precision = 28;
}
loop {
let unit = a[i];
let unit_v = unit.as_bytes_u128();
if bytes_v >= unit_v {
let unit_vd = Decimal::from(unit_v);
if let Some(quotient) = is_zero_remainder_decimal(bytes_vd, unit_vd, precision) {
return (quotient, unit);
}
}
if i == 0 {
break;
}
i -= 1;
}
(bytes_vd, Unit::B)
}
}