use core::convert::TryFrom;
use core::str::FromStr;
#[cfg(feature = "serde")]
use alloc::string::String;
use alloc::fmt::{self, Display, Formatter};
use crate::{
get_char_from_bytes, read_xib, AdjustedByte, ByteError, ByteUnit, ValueIncorrectError,
};
#[cfg(feature = "serde")]
use crate::serde::ser::{Serialize, Serializer};
#[cfg(feature = "serde")]
use crate::serde::de::{Deserialize, Deserializer, Error as DeError, Unexpected, Visitor};
#[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 Byte {
#[inline]
pub fn from_unit(value: f64, unit: ByteUnit) -> Result<Byte, ByteError> {
if value < 0f64 {
return Err(ValueIncorrectError::Negative(value).into());
}
let bytes = get_bytes(value, unit);
Ok(Byte(bytes))
}
#[cfg(feature = "u128")]
#[inline]
pub const fn from_bytes(bytes: u128) -> Byte {
Byte(bytes)
}
#[cfg(not(feature = "u128"))]
#[inline]
pub const fn from_bytes(bytes: u64) -> Byte {
Byte(bytes)
}
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn from_str<S: AsRef<str>>(s: S) -> Result<Byte, ByteError> {
let s = s.as_ref().trim();
let mut bytes = s.bytes();
let mut value = match bytes.next() {
Some(e) => {
match e {
b'0'..=b'9' => f64::from(e - b'0'),
_ => {
return Err(
ValueIncorrectError::NotNumber(get_char_from_bytes(e, bytes)).into()
);
}
}
}
None => return Err(ValueIncorrectError::NoValue.into()),
};
let e = 'outer: loop {
match bytes.next() {
Some(e) => {
match e {
b'0'..=b'9' => {
value = value * 10.0 + f64::from(e - b'0');
}
b'.' => {
let mut i = 0.1;
loop {
match bytes.next() {
Some(e) => {
match e {
b'0'..=b'9' => {
value += f64::from(e - b'0') * i;
i /= 10.0;
}
_ => {
if (i * 10.0) as u8 == 1 {
return Err(ValueIncorrectError::NotNumber(
get_char_from_bytes(e, bytes),
)
.into());
}
match e {
b' ' => {
loop {
match bytes.next() {
Some(e) => {
match e {
b' ' => (),
_ => break 'outer Some(e),
}
}
None => break 'outer None,
}
}
}
_ => break 'outer Some(e),
}
}
}
}
None => {
if (i * 10.0) as u8 == 1 {
return Err(ValueIncorrectError::NotNumber(
get_char_from_bytes(e, bytes),
)
.into());
}
break 'outer None;
}
}
}
}
b' ' => {
loop {
match bytes.next() {
Some(e) => {
match e {
b' ' => (),
_ => break 'outer Some(e),
}
}
None => break 'outer None,
}
}
}
_ => break 'outer Some(e),
}
}
None => break None,
}
};
let unit = read_xib(e, bytes)?;
let bytes = get_bytes(value, unit);
Ok(Byte(bytes))
}
}
impl Byte {
#[cfg(feature = "u128")]
#[inline]
pub const fn get_bytes(&self) -> u128 {
self.0
}
#[cfg(not(feature = "u128"))]
#[inline]
pub const fn get_bytes(&self) -> u64 {
self.0
}
#[inline]
pub fn get_adjusted_unit(&self, unit: ByteUnit) -> AdjustedByte {
let bytes_f64 = self.0 as f64;
let value = bytes_f64 / unit.get_unit_bytes() as f64;
AdjustedByte {
value,
unit,
}
}
#[allow(clippy::collapsible_if)]
pub fn get_appropriate_unit(&self, binary_multiples: bool) -> AdjustedByte {
let bytes = self.0;
if binary_multiples {
#[cfg(feature = "u128")]
{
if bytes > n_zib_bytes!() {
return self.get_adjusted_unit(ByteUnit::ZiB);
} else if bytes > n_eib_bytes!() {
return self.get_adjusted_unit(ByteUnit::EiB);
}
}
if bytes > n_pib_bytes!() {
self.get_adjusted_unit(ByteUnit::PiB)
} else if bytes > n_tib_bytes!() {
self.get_adjusted_unit(ByteUnit::TiB)
} else if bytes > n_gib_bytes!() {
self.get_adjusted_unit(ByteUnit::GiB)
} else if bytes > n_mib_bytes!() {
self.get_adjusted_unit(ByteUnit::MiB)
} else if bytes > n_kib_bytes!() {
self.get_adjusted_unit(ByteUnit::KiB)
} else {
self.get_adjusted_unit(ByteUnit::B)
}
} else {
#[cfg(feature = "u128")]
{
if bytes > n_zb_bytes!() {
return self.get_adjusted_unit(ByteUnit::ZB);
} else if bytes > n_eb_bytes!() {
return self.get_adjusted_unit(ByteUnit::EB);
}
}
if bytes > n_pb_bytes!() {
self.get_adjusted_unit(ByteUnit::PB)
} else if bytes > n_tb_bytes!() {
self.get_adjusted_unit(ByteUnit::TB)
} else if bytes > n_gb_bytes!() {
self.get_adjusted_unit(ByteUnit::GB)
} else if bytes > n_mb_bytes!() {
self.get_adjusted_unit(ByteUnit::MB)
} else if bytes > n_kb_bytes!() {
self.get_adjusted_unit(ByteUnit::KB)
} else {
self.get_adjusted_unit(ByteUnit::B)
}
}
}
}
impl Display for Byte {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
f.write_fmt(format_args!("{}", self.0))
}
}
#[cfg(feature = "u128")]
impl From<Byte> for u128 {
#[inline]
fn from(b: Byte) -> u128 {
b.0
}
}
#[cfg(not(feature = "u128"))]
impl From<Byte> for u64 {
#[inline]
fn from(b: Byte) -> u64 {
b.0
}
}
#[cfg(feature = "u128")]
impl From<u128> for Byte {
#[inline]
fn from(u: u128) -> Self {
Byte::from_bytes(u)
}
}
#[cfg(feature = "u128")]
impl From<usize> for Byte {
#[inline]
fn from(u: usize) -> Self {
Byte::from_bytes(u as u128)
}
}
#[cfg(not(feature = "u128"))]
impl From<usize> for Byte {
#[inline]
fn from(u: usize) -> Self {
Byte::from_bytes(u as u64)
}
}
#[cfg(feature = "u128")]
impl From<u64> for Byte {
#[inline]
fn from(u: u64) -> Self {
Byte::from_bytes(u as u128)
}
}
#[cfg(not(feature = "u128"))]
impl From<u64> for Byte {
#[inline]
fn from(u: u64) -> Self {
Byte::from_bytes(u)
}
}
#[cfg(feature = "u128")]
impl From<u32> for Byte {
#[inline]
fn from(u: u32) -> Self {
Byte::from_bytes(u as u128)
}
}
#[cfg(not(feature = "u128"))]
impl From<u32> for Byte {
#[inline]
fn from(u: u32) -> Self {
Byte::from_bytes(u as u64)
}
}
#[cfg(feature = "u128")]
impl From<u16> for Byte {
#[inline]
fn from(u: u16) -> Self {
Byte::from_bytes(u as u128)
}
}
#[cfg(not(feature = "u128"))]
impl From<u16> for Byte {
#[inline]
fn from(u: u16) -> Self {
Byte::from_bytes(u as u64)
}
}
#[cfg(feature = "u128")]
impl From<u8> for Byte {
#[inline]
fn from(u: u8) -> Self {
Byte::from_bytes(u as u128)
}
}
#[cfg(not(feature = "u128"))]
impl From<u8> for Byte {
#[inline]
fn from(u: u8) -> Self {
Byte::from_bytes(u as u64)
}
}
impl TryFrom<&str> for Byte {
type Error = ByteError;
#[inline]
fn try_from(s: &str) -> Result<Self, Self::Error> {
Byte::from_str(s)
}
}
impl FromStr for Byte {
type Err = ByteError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Byte::from_str(s)
}
}
#[cfg(feature = "u128")]
#[inline]
pub(crate) fn get_bytes(value: f64, unit: ByteUnit) -> u128 {
match unit {
ByteUnit::B => value as u128,
ByteUnit::KB => n_kb_bytes!(value, f64),
ByteUnit::KiB => n_kib_bytes!(value, f64),
ByteUnit::MB => n_mb_bytes!(value, f64),
ByteUnit::MiB => n_mib_bytes!(value, f64),
ByteUnit::GB => n_gb_bytes!(value, f64),
ByteUnit::GiB => n_gib_bytes!(value, f64),
ByteUnit::TB => n_tb_bytes!(value, f64),
ByteUnit::TiB => n_gib_bytes!(value, f64),
ByteUnit::PB => n_pb_bytes!(value, f64),
ByteUnit::PiB => n_pib_bytes!(value, f64),
ByteUnit::EB => n_eb_bytes!(value, f64),
ByteUnit::EiB => n_eib_bytes!(value, f64),
ByteUnit::ZB => n_zb_bytes!(value, f64),
ByteUnit::ZiB => n_zib_bytes!(value, f64),
}
}
#[cfg(not(feature = "u128"))]
#[inline]
pub(crate) fn get_bytes(value: f64, unit: ByteUnit) -> u64 {
match unit {
ByteUnit::B => value as u64,
ByteUnit::KB => n_kb_bytes!(value, f64),
ByteUnit::KiB => n_kib_bytes!(value, f64),
ByteUnit::MB => n_mb_bytes!(value, f64),
ByteUnit::MiB => n_mib_bytes!(value, f64),
ByteUnit::GB => n_gb_bytes!(value, f64),
ByteUnit::GiB => n_gib_bytes!(value, f64),
ByteUnit::TB => n_tb_bytes!(value, f64),
ByteUnit::TiB => n_gib_bytes!(value, f64),
ByteUnit::PB => n_pb_bytes!(value, f64),
ByteUnit::PiB => n_pib_bytes!(value, f64),
}
}
#[cfg(feature = "serde")]
impl Serialize for Byte {
#[allow(unreachable_code)]
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer, {
#[cfg(feature = "u128")]
{
serde_if_integer128! {
return serializer.serialize_u128(self.get_bytes());
}
unreachable!("the `integer128` feature of the `serde` crate needs to be enabled")
}
#[cfg(not(feature = "u128"))]
{
serializer.serialize_u64(self.get_bytes())
}
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Byte {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>, {
struct ByteVisitor;
impl<'de> Visitor<'de> for ByteVisitor {
type Value = Byte;
serde_if_integer128! {
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: DeError,
{
if v < 0 {
Err(DeError::invalid_value(Unexpected::Other(format!("integer `{}`", v).as_str()), &self))
} else {
#[cfg(feature = "u128")]
{
Ok(Byte::from_bytes(v as u128))
}
#[cfg(not(feature = "u128"))]
{
if v > u64::max_value() as i128 {
Err(DeError::invalid_value(Unexpected::Other(format!("integer `{}`", v).as_str()), &self))
} else {
Ok(Byte::from_bytes(v as u64))
}
}
}
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: DeError,
{
#[cfg(feature = "u128")]
{
Ok(Byte::from_bytes(v))
}
#[cfg(not(feature = "u128"))]
{
if v > u64::max_value() as u128 {
Err(DeError::invalid_value(Unexpected::Other(format!("integer `{}`", v).as_str()), &self))
} else {
Ok(Byte::from_bytes(v as u64))
}
}
}
}
#[inline]
fn expecting(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
f.write_str("a byte such as 123, \"123\", \"123KiB\" or \"50.84 MB\"")
}
#[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: DeError, {
Byte::from_str(v).map_err(DeError::custom)
}
#[inline]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: DeError, {
Byte::from_str(v.as_str()).map_err(DeError::custom)
}
#[inline]
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: DeError, {
if v < 0 {
Err(DeError::invalid_value(Unexpected::Signed(v), &self))
} else {
#[cfg(feature = "u128")]
{
Ok(Byte::from_bytes(v as u128))
}
#[cfg(not(feature = "u128"))]
{
Ok(Byte::from_bytes(v as u64))
}
}
}
#[inline]
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: DeError, {
#[cfg(feature = "u128")]
{
Ok(Byte::from_bytes(v as u128))
}
#[cfg(not(feature = "u128"))]
{
Ok(Byte::from_bytes(v))
}
}
#[inline]
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: DeError, {
Byte::from_unit(v, ByteUnit::B).map_err(DeError::custom)
}
}
deserializer.deserialize_any(ByteVisitor)
}
}