mod adjusted;
mod built_in_traits;
mod constants;
mod decimal;
mod parse;
#[cfg(feature = "rocket")]
mod rocket_traits;
#[cfg(feature = "schemars")]
mod schemars_traits;
#[cfg(feature = "serde")]
mod serde_traits;
use core::fmt::{self, Alignment, Display, Formatter, Write};
pub use adjusted::*;
use rust_decimal::prelude::*;
use crate::{
common::{ceil_f32, ceil_f64},
Unit,
};
#[cfg(feature = "u128")]
const RONNABYTE: u128 = 1_000_000_000_000_000_000_000_000_000;
#[cfg(feature = "u128")]
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
pub struct Byte(u128);
#[cfg(not(feature = "u128"))]
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
pub struct Byte(u64);
impl Display for Byte {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if f.alternate() {
let precision = f.precision().unwrap_or(3);
let (mut value, unit) = self.get_recoverable_unit(false, precision);
value = value.normalize();
let space_length = if f.sign_plus() {
4 - unit.as_str().len()
} else if f.sign_minus() {
0
} else {
1
};
if let Some(mut width) = f.width() {
let l = unit.as_str().len() + space_length;
if width > l + 1 {
width -= l;
let alignment = f.align().unwrap_or(Alignment::Left);
match alignment {
Alignment::Left | Alignment::Center => {
f.write_fmt(format_args!("{value:<width$}"))?
},
Alignment::Right => f.write_fmt(format_args!("{value:>width$}"))?,
}
} else {
f.write_fmt(format_args!("{value}"))?;
}
} else {
f.write_fmt(format_args!("{value}"))?;
}
for _ in 0..space_length {
f.write_char(' ')?;
}
f.write_fmt(format_args!("{unit}"))
} else {
Display::fmt(&self.0, f)
}
}
}
impl Byte {
#[inline]
pub const fn from_u128(size: u128) -> Option<Self> {
#[cfg(feature = "u128")]
{
if size < RONNABYTE {
Some(Byte(size))
} else {
None
}
}
#[cfg(not(feature = "u128"))]
{
if size <= u64::MAX as u128 {
Some(Byte(size as u64))
} else {
None
}
}
}
#[inline]
pub const unsafe fn from_u128_unsafe(size: u128) -> Self {
#[cfg(feature = "u128")]
{
Byte(size)
}
#[cfg(not(feature = "u128"))]
{
Byte(size as u64)
}
}
#[inline]
pub const fn from_u64(size: u64) -> Self {
#[cfg(feature = "u128")]
{
Byte(size as u128)
}
#[cfg(not(feature = "u128"))]
{
Byte(size)
}
}
#[inline]
pub fn from_f64(size: f64) -> Option<Self> {
if size >= 0.0 {
#[cfg(feature = "u128")]
{
let size = ceil_f64(size) as u128;
if size < RONNABYTE {
Some(Byte(size))
} else {
None
}
}
#[cfg(not(feature = "u128"))]
{
let size = ceil_f64(size) as u64;
if size < u64::MAX {
Some(Byte(size))
} else {
None
}
}
} else {
None
}
}
#[inline]
pub fn from_f32(size: f32) -> Option<Self> {
if size >= 0.0 {
#[cfg(feature = "u128")]
{
let size = ceil_f32(size) as u128;
if size < RONNABYTE {
Some(Byte(size))
} else {
None
}
}
#[cfg(not(feature = "u128"))]
{
let size = ceil_f32(size) as u64;
if size < u64::MAX {
Some(Byte(size))
} else {
None
}
}
} else {
None
}
}
#[inline]
pub const fn from_i128(size: i128) -> Option<Self> {
if size >= 0 {
Self::from_u128(size as u128)
} else {
None
}
}
#[inline]
pub const fn from_i64(size: i64) -> Option<Self> {
if size >= 0 {
Some(Self::from_u64(size as u64))
} else {
None
}
}
}
impl Byte {
#[inline]
pub const fn from_u128_with_unit(size: u128, unit: Unit) -> Option<Self> {
let v = {
match unit {
Unit::Bit => {
if size & 11 > 0 {
(size >> 3) + 1
} else {
size >> 3
}
},
Unit::B => size,
_ => match size.checked_mul(unit.as_bytes_u128()) {
Some(v) => v,
None => return None,
},
}
};
Self::from_u128(v)
}
#[inline]
pub const fn from_u64_with_unit(size: u64, unit: Unit) -> Option<Self> {
#[cfg(feature = "u128")]
{
Self::from_u128_with_unit(size as u128, unit)
}
#[cfg(not(feature = "u128"))]
{
let v = {
match unit {
Unit::Bit => {
if size & 11 > 0 {
(size >> 3) + 1
} else {
size >> 3
}
},
Unit::B => size,
_ => match size.checked_mul(unit.as_bytes_u64()) {
Some(v) => v,
None => return None,
},
}
};
Some(Self::from_u64(v))
}
}
#[inline]
pub fn from_f64_with_unit(size: f64, unit: Unit) -> Option<Self> {
match Decimal::from_f64(size) {
Some(size) => Self::from_decimal_with_unit(size, unit),
None => None,
}
}
#[inline]
pub fn from_f32_with_unit(size: f32, unit: Unit) -> Option<Self> {
match Decimal::from_f32(size) {
Some(size) => Self::from_decimal_with_unit(size, unit),
None => None,
}
}
#[inline]
pub const fn from_i128_with_unit(size: i128, unit: Unit) -> Option<Self> {
if size >= 0 {
Self::from_u128_with_unit(size as u128, unit)
} else {
None
}
}
#[inline]
pub const fn from_i64_with_unit(size: i64, unit: Unit) -> Option<Self> {
if size >= 0 {
Self::from_u64_with_unit(size as u64, unit)
} else {
None
}
}
}
impl Byte {
#[inline]
pub const fn as_u128(self) -> u128 {
#[cfg(feature = "u128")]
{
self.0
}
#[cfg(not(feature = "u128"))]
{
self.0 as u128
}
}
#[inline]
pub const fn as_u64(self) -> u64 {
#[cfg(feature = "u128")]
{
if self.0 <= u64::MAX as u128 {
self.0 as u64
} else {
u64::MAX
}
}
#[cfg(not(feature = "u128"))]
{
self.0
}
}
#[inline]
pub const fn as_u64_checked(self) -> Option<u64> {
#[cfg(feature = "u128")]
{
if self.0 <= u64::MAX as u128 {
Some(self.0 as u64)
} else {
None
}
}
#[cfg(not(feature = "u128"))]
{
Some(self.0)
}
}
}
impl Byte {
#[inline]
pub const fn add(self, rhs: Byte) -> Option<Byte> {
match self.0.checked_add(rhs.0) {
Some(v) => Some(Byte(v)),
None => None,
}
}
#[inline]
pub const fn subtract(self, rhs: Byte) -> Option<Byte> {
match self.0.checked_sub(rhs.0) {
Some(v) => Some(Byte(v)),
None => None,
}
}
#[allow(unexpected_cfgs)]
#[inline]
pub const fn multiply(self, rhs: usize) -> Option<Byte> {
#[cfg(feature = "u128")]
{
match self.0.checked_mul(rhs as u128) {
Some(v) => Some(Byte(v)),
None => None,
}
}
#[cfg(not(feature = "u128"))]
{
#[cfg(target_pointer_width = "128")]
{
if rhs > u64::MAX as usize {
return None;
}
}
match self.0.checked_mul(rhs as u64) {
Some(v) => Some(Byte(v)),
None => None,
}
}
}
#[allow(unexpected_cfgs)]
#[inline]
pub const fn divide(self, rhs: usize) -> Option<Byte> {
#[cfg(feature = "u128")]
{
match self.0.checked_div(rhs as u128) {
Some(v) => Some(Byte(v)),
None => None,
}
}
#[cfg(not(feature = "u128"))]
{
#[cfg(target_pointer_width = "128")]
{
if rhs > u64::MAX as usize {
return None;
}
}
match self.0.checked_div(rhs as u64) {
Some(v) => Some(Byte(v)),
None => None,
}
}
}
#[inline]
pub(crate) const fn div_8(self) -> Byte {
Byte(self.0 / 8)
}
}
impl Byte {
#[inline]
pub const fn get_exact_unit(self, allow_in_bits: bool) -> (u128, Unit) {
let bytes_v = self.as_u128();
let a = if allow_in_bits { Unit::get_multiples() } else { Unit::get_multiples_bytes() };
let mut i = a.len() - 1;
loop {
let unit = a[i];
let unit_v = unit.as_bytes_u128();
if bytes_v >= unit_v && bytes_v % unit_v == 0 {
return (bytes_v / unit_v, unit);
}
if i == 0 {
break;
}
i -= 1;
}
(bytes_v, Unit::B)
}
}