byte-unit-5.1.4/.cargo_vcs_info.json0000644000000001360000000000100127630ustar { "git": { "sha1": "fb2e4b7c61cdf0b6c88e7f65798dd9e65f5fb436" }, "path_in_vcs": "" }byte-unit-5.1.4/Cargo.toml0000644000000032510000000000100107620ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.69" name = "byte-unit" version = "5.1.4" authors = ["Magic Len "] include = [ "src/**/*", "Cargo.toml", "README.md", "LICENSE", ] description = "A library for interacting with units of bytes." homepage = "https://magiclen.org/byte-unit" readme = "README.md" keywords = [ "byte", "unit", "kb", "mb", "gb", ] categories = [ "no-std", "parser-implementations", "value-formatting", ] license = "MIT" repository = "https://github.com/magiclen/byte-unit" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [dependencies.rocket] version = "0.5" optional = true [dependencies.rust_decimal] version = "1" optional = true default-features = false [dependencies.serde] version = "1" features = ["alloc"] optional = true default-features = false [dependencies.utf8-width] version = "0.1" [dev-dependencies.serde_json] version = "1" [features] bit = ["rust_decimal"] byte = ["rust_decimal"] default = [ "std", "byte", ] rocket = [ "dep:rocket", "std", ] rust_decimal = ["dep:rust_decimal"] serde = ["dep:serde"] std = [ "serde?/std", "rust_decimal?/std", ] u128 = [] byte-unit-5.1.4/Cargo.toml.orig000064400000000000000000000020671046102023000144470ustar 00000000000000[package] name = "byte-unit" version = "5.1.4" authors = ["Magic Len "] edition = "2021" rust-version = "1.69" repository = "https://github.com/magiclen/byte-unit" homepage = "https://magiclen.org/byte-unit" keywords = ["byte", "unit", "kb", "mb", "gb"] categories = ["no-std", "parser-implementations", "value-formatting"] description = "A library for interacting with units of bytes." license = "MIT" include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"] [dependencies] utf8-width = "0.1" serde = { version = "1", default-features = false, features = ["alloc"], optional = true } rocket = { version = "0.5", optional = true } rust_decimal = { version = "1", default-features = false, optional = true } [dev-dependencies] serde_json = "1" [features] default = ["std", "byte"] serde = ["dep:serde"] rocket = ["dep:rocket", "std"] rust_decimal = ["dep:rust_decimal"] std = ["serde?/std", "rust_decimal?/std"] u128 = [] byte = ["rust_decimal"] bit = ["rust_decimal"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] byte-unit-5.1.4/LICENSE000064400000000000000000000020661046102023000125640ustar 00000000000000MIT License Copyright (c) 2023 magiclen.org (Ron Li) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. byte-unit-5.1.4/README.md000064400000000000000000000122701046102023000130340ustar 00000000000000Byte Unit ==================== [![CI](https://github.com/magiclen/Byte-Unit/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/Byte-Unit/actions/workflows/ci.yml) A library for interaction with units of bytes. The units are **B** for 1 byte, **KB** for 1000 bytes, **MiB** for 1048576 bytes, **GB** for 1000000000 bytes, etc, and up to **E** or **Y** (if the `u128` feature is enabled). ## Usage The data types for storing the size in bits/bytes are `u64` by default, meaning the highest supported unit is up to **E**. If the `u128` feature is enabled, the data types will use `u128`, increasing the highest supported unit up to **Y**. ### Unit The enum `Unit` can be used for representing the unit of bits/bytes. ```rust use byte_unit::Unit; assert_eq!("KB", Unit::KB.as_str()); assert_eq!("MiB", Unit::MiB.as_str()); assert_eq!(Unit::KB, Unit::parse_str("K", true, true).unwrap()); assert_eq!(Unit::Kbit, Unit::parse_str("K", true, false).unwrap()); assert_eq!(Unit::KB, Unit::parse_str("KB", true, true).unwrap()); assert_eq!(Unit::KB, Unit::parse_str("Kb", true, true).unwrap()); assert_eq!(Unit::Kbit, Unit::parse_str("Kbit", true, true).unwrap()); assert_eq!(Unit::KB, Unit::parse_str("KB", false, true).unwrap()); assert_eq!(Unit::Kbit, Unit::parse_str("Kb", false, true).unwrap()); ``` ### Byte The `Byte` struct can be used for representing a size in bytes. The `from_*` associated functions can be used to create a `Byte` instance from different data types. The `as_*` methods can retrieve the size as a primitive type. ```rust use byte_unit::{Byte, Unit}; assert_eq!(15000, Byte::from_u64(15000).as_u64()); assert_eq!(15000, Byte::from_u64_with_unit(15, Unit::KB).unwrap().as_u64()); ``` You can also parse a string to create a `Byte` instance. ```rust use byte_unit::Byte; assert_eq!(50840000, Byte::parse_str("50.84 MB", true).unwrap().as_u64()); ``` A `Byte` instance can be formatted to string precisely. For more detailed usage, please refer to the implementation documentation of `Display::fmt` for `Byte`. ```rust use byte_unit::Byte; let byte = Byte::from_u64(15500); assert_eq!("15500", byte.to_string()); assert_eq!("15.5 KB", format!("{byte:#}")); assert_eq!("15500 B", format!("{byte:#.0}")); ``` #### Arithmetic There are `add`, `subtract`, `multiply`, and `divide` methods. ```rust use byte_unit::Byte; let a = Byte::from_u64(15500); let b = Byte::from_u64(500); assert_eq!(16000, a.add(b).unwrap().as_u64()); assert_eq!(15000, a.subtract(b).unwrap().as_u64()); assert_eq!(31000, a.multiply(2).unwrap().as_u64()); assert_eq!(3100, a.divide(5).unwrap().as_u64()); ``` #### Find Out an Appropriate Unit The `get_exact_unit` and `get_recoverable_unit` methods is useful if you want to find out a unit that is appropriate for a `Byte` instance. ```rust use byte_unit::{Byte, Unit}; let byte = Byte::from_u64(50840000); assert_eq!((50840, Unit::KB), byte.get_exact_unit(false)); assert_eq!((50.84f64.try_into().unwrap(), Unit::MB), byte.get_recoverable_unit(false, 2)); assert_eq!((50840.into(), Unit::KB), byte.get_recoverable_unit(false, 0)); ``` #### AdjustedByte The `AdjustedByte` struct can be used for roughly representing a size of bytes with a unit. To change the unit of a `Byte` instance, you can use the `get_adjusted_unit` method. An `AdjustedByte` instance can be formatted to string. For more detailed usage, please refer to the implementation documentation of `Display::fmt` for `AdjustedByte`. ```rust use byte_unit::{Byte, Unit}; let byte = Byte::parse_str("123KiB", true).unwrap(); let adjusted_byte = byte.get_adjusted_unit(Unit::KB); assert_eq!("125.952 KB", adjusted_byte.to_string()); assert_eq!("125.95 KB", format!("{adjusted_byte:.2}")); ``` The `get_appropriate_unit` method can be used to automatically find an appropriate unit for creating an `AdjustedByte` instance. ```rust use byte_unit::{Byte, Unit, UnitType}; let byte = Byte::from_u64(1500000); let adjusted_byte = byte.get_appropriate_unit(UnitType::Binary); assert_eq!("1.43 MiB", format!("{adjusted_byte:.2}")); ``` ### Bit The `Bit` struct can be used for representing a size in bits. The `bit` feature must be enabled. Usage of the `Bit` struct and the `Byte` struct is very similar. Also, There is the `AdjustedBit` struct. The difference lies in the fact that the `parse_str` method of the `Bit` struct cannot be configured to ignore case; it always does not ignore case. ```rust use byte_unit::{Bit, Unit}; let bit = Bit::parse_str("123Kib").unwrap(); let adjusted_bit = bit.get_adjusted_unit(Unit::Kbit); assert_eq!("125.952 Kb", adjusted_bit.to_string()); assert_eq!("125.95 Kb", format!("{adjusted_bit:.2}")); ``` ## No Std Disable the default features to compile this crate without std. ```toml [dependencies.byte-unit] version = "*" default-features = false features = ["byte"] ``` ## Serde Support Enable the `serde` feature to support the serde framework. ```toml [dependencies.byte-unit] version = "*" features = ["serde"] ``` ## Rocket Support Enable the `rocket` feature to support the Rocket framework. ```toml [dependencies.byte-unit] version = "*" features = ["rocket"] ``` ## Crates.io https://crates.io/crates/byte-unit ## Documentation https://docs.rs/byte-unit ## License [MIT](LICENSE) byte-unit-5.1.4/src/bit/adjusted/built_in_traits.rs000064400000000000000000000020601046102023000204620ustar 00000000000000use core::str::FromStr; use super::{AdjustedBit, Bit, Unit, UnitType}; use crate::ParseError; impl From for AdjustedBit { /// `unit_type` is set to `UnitType::Both`. See [`Bit::get_appropriate_unit`](./struct.Bit.html#method.get_appropriate_unit). #[inline] fn from(value: Bit) -> Self { value.get_appropriate_unit(UnitType::Both) } } impl From for f64 { #[inline] fn from(value: AdjustedBit) -> Self { value.get_value() } } impl From for Unit { #[inline] fn from(value: AdjustedBit) -> Self { value.get_unit() } } impl From for Bit { #[inline] fn from(value: AdjustedBit) -> Self { value.get_bit() } } impl FromStr for AdjustedBit { type Err = ParseError; /// * `unit_type` is set to `UnitType::Both`. See [`Bit::get_appropriate_unit`](./struct.Bit.html#method.get_appropriate_unit). #[inline] fn from_str(s: &str) -> Result { Ok(Bit::parse_str(s)?.get_appropriate_unit(UnitType::Both)) } } byte-unit-5.1.4/src/bit/adjusted/mod.rs000064400000000000000000000224711046102023000160560ustar 00000000000000mod built_in_traits; #[cfg(feature = "rocket")] mod rocket_traits; #[cfg(feature = "serde")] mod serde_traits; use core::{ cmp::Ordering, fmt::{self, Alignment, Display, Formatter, Write}, }; use super::{Bit, Unit}; use crate::{common::round_fractional_part_f64, UnitType}; /// Generated from the [`Bit::get_adjusted_unit`](./struct.Bit.html#method.get_adjusted_unit) method or the the [`Bit::get_appropriate_unit`](./struct.Bit.html#method.get_appropriate_unit) method. /// /// For accuracy representation, utilize the `Bit` struct. #[derive(Debug, Clone, Copy)] pub struct AdjustedBit { pub(crate) value: f64, pub(crate) unit: Unit, } impl PartialEq for AdjustedBit { #[inline] fn eq(&self, other: &AdjustedBit) -> bool { let s = self.get_bit(); let o = other.get_bit(); s.eq(&o) } } impl Eq for AdjustedBit {} impl PartialOrd for AdjustedBit { #[inline] fn partial_cmp(&self, other: &AdjustedBit) -> Option { Some(self.cmp(other)) } } impl Ord for AdjustedBit { #[inline] fn cmp(&self, other: &AdjustedBit) -> Ordering { let s = self.get_bit(); let o = other.get_bit(); s.cmp(&o) } } impl Display for AdjustedBit { /// Formats the value using the given formatter. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64_with_unit(1555, Unit::Kbit).unwrap(); /// /// let adjusted_bit = bit.get_adjusted_unit(Unit::Mbit); /// /// assert_eq!("1.555 Mb", adjusted_bit.to_string()); /// ``` /// /// ``` /// use byte_unit::{Bit, UnitType}; /// /// let bit = Bit::from_u64(10000); /// /// let adjusted_bit_based_2 = bit.get_appropriate_unit(UnitType::Binary); /// let adjusted_bit_based_10 = bit.get_appropriate_unit(UnitType::Decimal); /// /// assert_eq!("9.765625 Kib", format!("{adjusted_bit_based_2}")); /// assert_eq!("10 Kb", format!("{adjusted_bit_based_10}")); /// /// // with precision /// assert_eq!("9.77 Kib", format!("{adjusted_bit_based_2:.2}")); /// assert_eq!("10.00 Kb", format!("{adjusted_bit_based_10:.2}")); /// /// // without any unnecessary fractional part /// assert_eq!("9.77 Kib", format!("{adjusted_bit_based_2:#.2}")); /// assert_eq!("10 Kb", format!("{adjusted_bit_based_10:#.2}")); /// /// // with a width, left alignment /// assert_eq!("9.77 Kib", format!("{adjusted_bit_based_2:10.2}")); /// assert_eq!("10.00 Kb", format!("{adjusted_bit_based_10:10.2}")); /// /// // with a width, right alignment /// assert_eq!(" 9.77 Kib", format!("{adjusted_bit_based_2:>10.2}")); /// assert_eq!(" 10.00 Kb", format!("{adjusted_bit_based_10:>10.2}")); /// /// // with a width, right alignment, more spaces between the value and the unit /// assert_eq!(" 9.77 Kib", format!("{adjusted_bit_based_2:>+10.2}")); /// assert_eq!(" 10.00 Kb", format!("{adjusted_bit_based_10:>+10.2}")); /// /// // no spaces between the value and the unit /// assert_eq!("9.765625Kib", format!("{adjusted_bit_based_2:-}")); /// assert_eq!("10Kb", format!("{adjusted_bit_based_10:-}")); /// ``` fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let Self { value, unit, } = self; let handle_basic_precision = |precision: usize, f: &mut Formatter<'_>| -> fmt::Result { if f.alternate() { let value = round_fractional_part_f64(*value, precision); f.write_fmt(format_args!("{value}")) } else if matches!(unit, Unit::Bit | Unit::B) { f.write_fmt(format_args!("{value}")) } else { f.write_fmt(format_args!("{value:.precision$}")) } }; 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 let Some(precision) = f.precision() { if width > l + 1 { width -= l; let alignment = f.align().unwrap_or(Alignment::Left); if f.alternate() { let value = round_fractional_part_f64(*value, precision); match alignment { Alignment::Left | Alignment::Center => { f.write_fmt(format_args!("{value: f.write_fmt(format_args!("{value:>width$}"))?, } } else { match alignment { Alignment::Left | Alignment::Center => { f.write_fmt(format_args!("{value: { f.write_fmt(format_args!("{value:>width$.precision$}"))? }, } } } else { handle_basic_precision(precision, f)?; } } else 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: f.write_fmt(format_args!("{value:>width$}"))?, } } else { f.write_fmt(format_args!("{value}"))?; } } else if let Some(precision) = f.precision() { handle_basic_precision(precision, f)?; } else { f.write_fmt(format_args!("{value}"))?; } for _ in 0..space_length { f.write_char(' ')?; } f.write_fmt(format_args!("{unit}")) } } /// Methods for getting values. impl AdjustedBit { /// Get the value. #[inline] pub const fn get_value(&self) -> f64 { self.value } /// Get the unit. #[inline] pub const fn get_unit(&self) -> Unit { self.unit } /// Create a new `Bit` instance from this `AdjustedBit` instance. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64_with_unit(1555, Unit::Kbit).unwrap(); /// /// let adjusted_bit = bit.get_adjusted_unit(Unit::Mbit); /// /// let bit_back = adjusted_bit.get_bit(); /// /// assert_eq!(bit, bit_back); /// ``` /// /// # Points to Note /// /// * The result may not be logically equal to the original `Bit` instance due to the accuracy of floating-point numbers. #[inline] pub fn get_bit(&self) -> Bit { Bit::from_f64_with_unit(self.value, self.unit).unwrap() } } /// Associated functions for generating `AdjustedBit`. impl Bit { /// Adjust the unit and value for this `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::{AdjustedBit, Bit, Unit}; /// /// let bit = Bit::parse_str("123Kib").unwrap(); /// /// let adjusted_bit = bit.get_adjusted_unit(Unit::Kbit); /// /// assert_eq!("125.952 Kb", adjusted_bit.to_string()); /// ``` /// /// ``` /// use byte_unit::{AdjustedBit, Bit, Unit}; /// /// let bit = Bit::parse_str("50.84 Mb").unwrap(); /// /// let adjusted_bit = bit.get_adjusted_unit(Unit::Mibit); /// /// assert_eq!("48.48480224609375 Mib", adjusted_bit.to_string()); /// ``` #[inline] pub fn get_adjusted_unit(self, unit: Unit) -> AdjustedBit { let bit_v = self.as_u128(); let value = match unit { Unit::Bit => (bit_v << 3) as f64, Unit::B => bit_v as f64, _ => bit_v as f64 / unit.as_bits_u128() as f64, }; AdjustedBit { value, unit, } } /// Find the appropriate unit and value for this `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, UnitType}; /// /// let bit = Bit::parse_str("123Kib").unwrap(); /// /// let adjusted_bit = bit.get_appropriate_unit(UnitType::Decimal); /// /// assert_eq!("125.952 Kb", adjusted_bit.to_string()); /// ``` /// /// ``` /// use byte_unit::{Bit, UnitType}; /// /// let bit = Bit::parse_str("50.84 Mb").unwrap(); /// /// let adjusted_bit = bit.get_appropriate_unit(UnitType::Binary); /// /// assert_eq!("48.48480224609375 Mib", adjusted_bit.to_string()); /// ``` pub fn get_appropriate_unit(&self, unit_type: UnitType) -> AdjustedBit { let a = Unit::get_multiples_bits(); let (skip, step) = match unit_type { UnitType::Binary => (0, 2), UnitType::Decimal => (1, 2), UnitType::Both => (0, 1), }; let bits_v = self.as_u128(); for unit in a.iter().rev().skip(skip).step_by(step) { if bits_v >= unit.as_bits_u128() { return self.get_adjusted_unit(*unit); } } self.get_adjusted_unit(Unit::B) } } byte-unit-5.1.4/src/bit/adjusted/rocket_traits.rs000064400000000000000000000010321046102023000201420ustar 00000000000000use std::str::FromStr; use rocket::{ form::{self, FromFormField, ValueField}, request::FromParam, }; use super::AdjustedBit; use crate::ParseError; impl<'r> FromParam<'r> for AdjustedBit { type Error = ParseError; #[inline] fn from_param(v: &'r str) -> Result { Self::from_str(v) } } impl<'r> FromFormField<'r> for AdjustedBit { #[inline] fn from_value(v: ValueField<'r>) -> form::Result<'r, Self> { Ok(Self::from_str(v.value).map_err(form::Error::custom)?) } } byte-unit-5.1.4/src/bit/adjusted/serde_traits.rs000064400000000000000000000024631046102023000177660ustar 00000000000000use core::{ fmt::{self, Formatter}, str::FromStr, }; use serde::{ self, de::{Error as DeError, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use super::AdjustedBit; impl Serialize for AdjustedBit { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { serializer.serialize_str(format!("{:#}", self).as_str()) } else { serializer.serialize_str(format!("{:-#}", self).as_str()) } } } impl<'de> Deserialize<'de> for AdjustedBit { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct MyVisitor; impl<'de> Visitor<'de> for MyVisitor { type Value = AdjustedBit; #[inline] fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a string such as \"123\", \"123Kib\", \"50.84 Mb\"") } #[inline] fn visit_str(self, v: &str) -> Result where E: DeError, { AdjustedBit::from_str(v).map_err(DeError::custom) } } deserializer.deserialize_str(MyVisitor) } } byte-unit-5.1.4/src/bit/built_in_traits.rs000064400000000000000000000151061046102023000166640ustar 00000000000000use core::{cmp::Ordering, str::FromStr}; use super::Bit; use crate::{ExceededBoundsError, ParseError, TryFromIntError}; impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: u128) -> Result { Bit::from_u128(value).ok_or(ExceededBoundsError) } } impl From for Bit { #[inline] fn from(value: u64) -> Self { Bit::from_u64(value) } } impl From for Bit { #[inline] fn from(value: u32) -> Self { Bit::from_u64(value as u64) } } impl From for Bit { #[inline] fn from(value: u16) -> Self { Bit::from_u64(value as u64) } } impl From for Bit { #[inline] fn from(value: u8) -> Self { Bit::from_u64(value as u64) } } impl From for Bit { #[inline] fn from(value: usize) -> Self { #[cfg(target_pointer_width = "128")] { Byte::from_u128(value as u128).unwrap_or(Byte::MAX) } #[cfg(not(target_pointer_width = "128"))] { Bit::from_u64(value as u64) } } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: i128) -> Result { Bit::from_i128(value).ok_or(ExceededBoundsError) } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: i64) -> Result { Bit::from_i64(value).ok_or(ExceededBoundsError) } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: i32) -> Result { Bit::from_i64(value as i64).ok_or(ExceededBoundsError) } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: i16) -> Result { Bit::from_i64(value as i64).ok_or(ExceededBoundsError) } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: i8) -> Result { Bit::from_i64(value as i64).ok_or(ExceededBoundsError) } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: isize) -> Result { #[cfg(target_pointer_width = "128")] { Bit::from_i128(value as i128).ok_or(ExceededBoundsError) } #[cfg(not(target_pointer_width = "128"))] { Bit::from_i64(value as i64).ok_or(ExceededBoundsError) } } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: f64) -> Result { Bit::from_f64(value).ok_or(ExceededBoundsError) } } impl TryFrom for Bit { type Error = ExceededBoundsError; #[inline] fn try_from(value: f32) -> Result { Bit::from_f32(value).ok_or(ExceededBoundsError) } } impl From for u128 { #[inline] fn from(bit: Bit) -> Self { bit.as_u128() } } impl From for u64 { #[inline] fn from(bit: Bit) -> Self { bit.as_u64() } } impl TryFrom for u32 { type Error = TryFromIntError; #[inline] fn try_from(bit: Bit) -> Result { u32::try_from(bit.as_u64()) } } impl TryFrom for u16 { type Error = TryFromIntError; #[inline] fn try_from(bit: Bit) -> Result { u16::try_from(bit.as_u64()) } } impl TryFrom for u8 { type Error = TryFromIntError; #[inline] fn try_from(bit: Bit) -> Result { u8::try_from(bit.as_u64()) } } impl TryFrom for usize { type Error = TryFromIntError; #[inline] fn try_from(bit: Bit) -> Result { #[cfg(target_pointer_width = "128")] { usize::try_from(bit.as_u128()) } #[cfg(not(target_pointer_width = "128"))] { usize::try_from(bit.as_u64()) } } } impl FromStr for Bit { type Err = ParseError; #[inline] fn from_str(s: &str) -> Result { Bit::parse_str(s) } } impl PartialEq for Bit { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &u64) -> bool { self.0 == *other as u128 } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &u64) -> bool { self.0 == *other } } impl PartialEq for Bit { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &u128) -> bool { self.0 == *other } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &u128) -> bool { self.0 as u128 == *other } } impl PartialEq for u64 { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &Bit) -> bool { *self as u128 == other.0 } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &Bit) -> bool { *self == other.0 } } impl PartialEq for u128 { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &Bit) -> bool { *self == other.0 } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &Bit) -> bool { *self == other.0 as u128 } } impl PartialOrd for Bit { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &u64) -> Option { self.0.partial_cmp(&(*other as u128)) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &u64) -> Option { self.0.partial_cmp(other) } } impl PartialOrd for Bit { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &u128) -> Option { self.0.partial_cmp(other) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &u128) -> Option { (self.0 as u128).partial_cmp(other) } } impl PartialOrd for u64 { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &Bit) -> Option { (*self as u128).partial_cmp(&other.0) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &Bit) -> Option { self.partial_cmp(&other.0) } } impl PartialOrd for u128 { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &Bit) -> Option { self.partial_cmp(&other.0) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &Bit) -> Option { self.partial_cmp(&(other.0 as u128)) } } byte-unit-5.1.4/src/bit/constants.rs000064400000000000000000000070461046102023000155110ustar 00000000000000use super::Bit; #[cfg(feature = "u128")] use super::RONNABIT; /// Constant `Bit`s. #[rustfmt::skip] impl Bit { /// One bit. pub const BIT: Bit = Bit(1); /// 1 Kbit = 103 bits. pub const KILOBIT: Bit = Bit(1_000); /// 1 Mbit = 106 bits. pub const MEGABIT: Bit = Bit(1_000_000); /// 1 Gbit = 109 bits. pub const GIGABIT: Bit = Bit(1_000_000_000); /// 1 Tbit = 1012 bits. pub const TERABIT: Bit = Bit(1_000_000_000_000); /// 1 Pbit = 1015 bits. pub const PETABIT: Bit = Bit(1_000_000_000_000_000); /// 1 Ebit = 1018 bits. pub const EXABIT: Bit = Bit(1_000_000_000_000_000_000); #[cfg(feature = "u128")] /// 1 Zbit = 1021 bits. pub const ZETTABIT: Bit = Bit(1_000_000_000_000_000_000_000); #[cfg(feature = "u128")] /// 1 Ybit = 1024 bits. pub const YOTTABIT: Bit = Bit(1_000_000_000_000_000_000_000_000); /// 1 Kibit = 210 bits. pub const KIBIBIT: Bit = Bit(1 << 10); /// 1 Mibit = 220 bits. pub const MEBIBIT: Bit = Bit(1 << 20); /// 1 Gibit = 230 bits. pub const GIBIBIT: Bit = Bit(1 << 30); /// 1 Tibit = 240 bits. pub const TEBIBIT: Bit = Bit(1 << 40); /// 1 Pibit = 250 bits. pub const PEBIBIT: Bit = Bit(1 << 50); /// 1 Eibit = 260 bits. pub const EXBIBIT: Bit = Bit(1 << 60); #[cfg(feature = "u128")] /// 1 Zibit = 270 bits. pub const ZEBIBIT: Bit = Bit(1 << 70); #[cfg(feature = "u128")] /// 1 Yibit = 280 bits. pub const YOBIBIT: Bit = Bit(1 << 80); /// 1 KB = 8 * 103 bits. pub const KILOBYTE: Bit = Bit::KILOBIT.mul_8(); /// 1 MB = 8 * 106 bits. pub const MEGABYTE: Bit = Bit::MEGABIT.mul_8(); /// 1 GB = 8 * 109 bits. pub const GIGABYTE: Bit = Bit::GIGABIT.mul_8(); /// 1 TB = 8 * 1012 bits. pub const TERABYTE: Bit = Bit::TERABIT.mul_8(); /// 1 PB = 8 * 1015 bits. pub const PETABYTE: Bit = Bit::PETABIT.mul_8(); /// 1 EB = 8 * 1018 bits. pub const EXABYTE: Bit = Bit::EXABIT.mul_8(); #[cfg(feature = "u128")] /// 1 ZB = 8 * 1021 bits. pub const ZETTABYTE: Bit = Bit::ZETTABIT.mul_8(); #[cfg(feature = "u128")] /// 1 YB = 8 * 1024 bits. pub const YOTTABYTE: Bit = Bit::YOTTABIT.mul_8(); /// 1 KiB = 213 bits. pub const KIBIBYTE: Bit = Bit::KIBIBIT.mul_8(); /// 1 MiB = 223 bits. pub const MEBIBYTE: Bit = Bit::MEBIBIT.mul_8(); /// 1 GiB = 233 bits. pub const GIBIBYTE: Bit = Bit::GIBIBIT.mul_8(); /// 1 TiB = 243 bits. pub const TEBIBYTE: Bit = Bit::TEBIBIT.mul_8(); /// 1 PiB = 253 bits. pub const PEBIBYTE: Bit = Bit::PEBIBIT.mul_8(); /// 1 EiB = 263 bits. pub const EXBIBYTE: Bit = Bit::EXBIBIT.mul_8(); #[cfg(feature = "u128")] /// 1 ZiB = 273 bits. pub const ZEBIBYTE: Bit = Bit::ZEBIBIT.mul_8(); #[cfg(feature = "u128")] /// 1 YiB = 283 bits. pub const YOBIBYTE: Bit = Bit::YOBIBIT.mul_8(); /// 0 bit. pub const MIN: Bit = Bit(0); /// **1027 - 1** bits if the `u128` feature is enabled, or **264 - 1** otherwise. pub const MAX: Bit = { #[cfg(feature = "u128")] { Bit(RONNABIT - 1) } #[cfg(not(feature = "u128"))] { Bit(u64::MAX) } }; } byte-unit-5.1.4/src/bit/decimal.rs000064400000000000000000000105071046102023000150670ustar 00000000000000use rust_decimal::prelude::*; use super::Bit; use crate::{common::is_zero_remainder_decimal, Unit}; /// Associated functions for building `Bit` instances using `Decimal`. impl Bit { /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// use rust_decimal::Decimal; /// /// let bit = Bit::from_decimal(Decimal::from(15000000u64)).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or not greater than or equal to **0**, this function will return `None`. /// * The fractional part will be rounded up. #[inline] pub fn from_decimal(size: Decimal) -> Option { 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 } } } /// Associated functions for building `Bit` instances using `Decimal` (with `Unit`). impl Bit { /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// use rust_decimal::Decimal; /// /// let bit = Bit::from_decimal_with_unit(Decimal::from(15u64), Unit::Mbit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large or not greater than or equal to **0**, this function will return `None`. /// * The calculated bit will be rounded up. #[inline] pub fn from_decimal_with_unit(size: Decimal, unit: Unit) -> Option { let v = { match unit { Unit::Bit => size, _ => match size.checked_mul(Decimal::from(unit.as_bits_u128())) { Some(v) => v, None => return None, }, } }; Self::from_decimal(v) } } /// Methods for finding an unit using `Decimal`. impl Bit { /// Find the appropriate unit and value that can be used to recover back to this `Bit` precisely. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64(3670016); /// /// assert_eq!( /// (3.5f64.try_into().unwrap(), Unit::Mibit), /// bit.get_recoverable_unit(false, 3) /// ); /// ``` /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64(28000000); /// /// assert_eq!( /// (3.5f64.try_into().unwrap(), Unit::MB), /// bit.get_recoverable_unit(true, 3) /// ); /// ``` /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64(437500); /// /// assert_eq!( /// (437.5f64.try_into().unwrap(), Unit::Kbit), /// bit.get_recoverable_unit(false, 3) /// ); /// ``` /// /// # Points to Note /// /// * `precision` should be smaller or equal to `26` if the `u128` feature is enabled, otherwise `19`. The typical `precision` is `3`. #[inline] pub fn get_recoverable_unit( self, allow_in_bytes: bool, mut precision: usize, ) -> (Decimal, Unit) { let bits_v = self.as_u128(); let bits_vd = Decimal::from(bits_v); let a = if allow_in_bytes { Unit::get_multiples() } else { Unit::get_multiples_bits() }; let mut i = a.len() - 1; if precision >= 28 { precision = 28; } loop { let unit = a[i]; let unit_v = unit.as_bits_u128(); if bits_v >= unit_v { let unit_vd = Decimal::from(unit_v); if let Some(quotient) = is_zero_remainder_decimal(bits_vd, unit_vd, precision) { return (quotient, unit); } } if i == 0 { break; } i -= 1; } (bits_vd, Unit::Bit) } } byte-unit-5.1.4/src/bit/mod.rs000064400000000000000000000533571046102023000142620ustar 00000000000000mod adjusted; mod built_in_traits; mod constants; mod decimal; mod parse; #[cfg(feature = "rocket")] mod rocket_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 RONNABIT: u128 = 1_000_000_000_000_000_000_000_000_000; // RB #[cfg(feature = "u128")] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] /// Representing the size in bits. pub struct Bit(u128); #[cfg(not(feature = "u128"))] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] /// Representing the size in bits. pub struct Bit(u64); impl Display for Bit { /// Formats the value using the given formatter. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64_with_unit(1555, Unit::Kbit).unwrap(); /// /// assert_eq!("1555000", bit.to_string()); /// ``` /// /// ``` /// use byte_unit::{Bit, UnitType}; /// /// let bit_based_2 = Bit::from_u64(10240); /// let bit_based_10 = Bit::from_u64(10000); /// /// assert_eq!("10240", format!("{bit_based_2}")); /// assert_eq!("10000", format!("{bit_based_10}")); /// /// // with an exact unit /// assert_eq!("10 Kib", format!("{bit_based_2:#}")); /// assert_eq!("10 Kb", format!("{bit_based_10:#}")); /// /// // with an exact unit, no spaces between the value and the unit /// assert_eq!("10Kib", format!("{bit_based_2:-#}")); /// assert_eq!("10Kb", format!("{bit_based_10:-#}")); /// /// // with a width, left alignment /// assert_eq!("10 Kib", format!("{bit_based_2:#10}")); /// assert_eq!("10 Kb", format!("{bit_based_10:#10}")); /// /// // with a width, right alignment /// assert_eq!(" 10 Kib", format!("{bit_based_2:>#10}")); /// assert_eq!(" 10 Kb", format!("{bit_based_10:>#10}")); /// /// // with a width, right alignment, more spaces between the value and the unit /// assert_eq!(" 10 Kib", format!("{bit_based_2:>+#10}")); /// assert_eq!(" 10 Kb", format!("{bit_based_10:>+#10}")); /// ``` /// /// ``` /// use byte_unit::{Bit, UnitType}; /// /// let bit = Bit::from_u64(3211776); /// /// assert_eq!("3211776", format!("{bit}")); /// /// // with a unit, still precisely /// assert_eq!("3136.5 Kib", format!("{bit:#}")); /// /// // with a unit and a larger precision (default is 3), still precisely /// assert_eq!("3.211776 Mb", format!("{bit:#.6}")); /// /// // with a unit and a smaller precision (default is 3), still precisely /// assert_eq!("3211776 b", format!("{bit:#.0}")); /// ``` 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: 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) } } } /// Associated functions for building `Bit` instances. impl Bit { /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::from_u128(15000000).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise), this function will return `None`. #[inline] pub const fn from_u128(size: u128) -> Option { #[cfg(feature = "u128")] { if size < RONNABIT { Some(Bit(size)) } else { None } } #[cfg(not(feature = "u128"))] { if size <= u64::MAX as u128 { Some(Bit(size as u64)) } else { None } } } /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = unsafe { Bit::from_u128_unsafe(15000000) }; // 15 Mb /// ``` /// /// # Safety /// You must ensure the input **size** is not too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) on your own. #[inline] pub const unsafe fn from_u128_unsafe(size: u128) -> Self { #[cfg(feature = "u128")] { Bit(size) } #[cfg(not(feature = "u128"))] { Bit(size as u64) } } /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::from_u64(15000000); // 15 Mb /// ``` #[inline] pub const fn from_u64(size: u64) -> Self { #[cfg(feature = "u128")] { Bit(size as u128) } #[cfg(not(feature = "u128"))] { Bit(size) } } /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::from_f64(15000000.0).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or not greater than or equal to **0**, this function will return `None`. /// * The fractional part will be rounded up. #[inline] pub fn from_f64(size: f64) -> Option { if size >= 0.0 { #[cfg(feature = "u128")] { let size = ceil_f64(size) as u128; if size < RONNABIT { Some(Bit(size)) } else { None } } #[cfg(not(feature = "u128"))] { let size = ceil_f64(size) as u64; if size < u64::MAX { Some(Bit(size)) } else { None } } } else { None } } /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::from_f32(15000000.0).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or not greater than or equal to **0**, this function will return `None`. /// * The fractional part will be rounded up. #[inline] pub fn from_f32(size: f32) -> Option { if size >= 0.0 { #[cfg(feature = "u128")] { let size = ceil_f32(size) as u128; if size < RONNABIT { Some(Bit(size)) } else { None } } #[cfg(not(feature = "u128"))] { let size = ceil_f32(size) as u64; if size < u64::MAX { Some(Bit(size)) } else { None } } } else { None } } /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::from_i128(15000000).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or negative, this function will return `None`. #[inline] pub const fn from_i128(size: i128) -> Option { if size >= 0 { Self::from_u128(size as u128) } else { None } } /// Create a new `Bit` instance from a size in bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::from_i64(15000000).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the input **size** is negative, this function will return `None`. #[inline] pub const fn from_i64(size: i64) -> Option { if size >= 0 { Some(Self::from_u64(size as u64)) } else { None } } } /// Associated functions for building `Bit` instances (with `Unit`). impl Bit { /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u128_with_unit(15, Unit::Mbit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large, this function will return `None`. #[inline] pub const fn from_u128_with_unit(size: u128, unit: Unit) -> Option { let v = { match unit { Unit::Bit => size, _ => match size.checked_mul(unit.as_bits_u128()) { Some(v) => v, None => return None, }, } }; Self::from_u128(v) } /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64_with_unit(15, Unit::Mbit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large, this function will return `None`. /// * If the input **unit** is `Bit`, the calculated bit will be rounded up. #[inline] pub const fn from_u64_with_unit(size: u64, unit: Unit) -> Option { #[cfg(feature = "u128")] { Self::from_u128_with_unit(size as u128, unit) } #[cfg(not(feature = "u128"))] { let v = { match unit { Unit::Bit => size, _ => match size.checked_mul(unit.as_bits_u64()) { Some(v) => v, None => return None, }, } }; Some(Self::from_u64(v)) } } /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_f64_with_unit(15.0, Unit::Mbit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large or not greater than or equal to **0**, this function will return `None`. /// * The calculated bit will be rounded up. #[inline] pub fn from_f64_with_unit(size: f64, unit: Unit) -> Option { match Decimal::from_f64(size) { Some(size) => Self::from_decimal_with_unit(size, unit), None => None, } } /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_f32_with_unit(15.0, Unit::Mbit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large or not greater than or equal to **0**, this function will return `None`. /// * The calculated bit will be rounded up. #[inline] pub fn from_f32_with_unit(size: f32, unit: Unit) -> Option { match Decimal::from_f32(size) { Some(size) => Self::from_decimal_with_unit(size, unit), None => None, } } /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_i128_with_unit(15, Unit::Mibit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large or negative, this function will return `None`. #[inline] pub const fn from_i128_with_unit(size: i128, unit: Unit) -> Option { if size >= 0 { Self::from_u128_with_unit(size as u128, unit) } else { None } } /// Create a new `Bit` instance from a size of bits with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_i64_with_unit(15, Unit::Mbit).unwrap(); // 15 Mb /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large or negative, this function will return `None`. #[inline] pub const fn from_i64_with_unit(size: i64, unit: Unit) -> Option { if size >= 0 { Self::from_u64_with_unit(size as u64, unit) } else { None } } } /// Methods for converting a `Bit` instance into a primitive integer. impl Bit { /// Retrieve the bit represented by this `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let bit = Bit::parse_str("123KiB").unwrap(); /// /// let result = bit.as_u128(); /// /// assert_eq!(1007616, result); /// ``` /// /// ``` /// use byte_unit::Bit; /// /// let bit = Bit::parse_str("123Kib").unwrap(); /// /// let result = bit.as_u128(); /// /// assert_eq!(125952, result); /// ``` #[inline] pub const fn as_u128(self) -> u128 { #[cfg(feature = "u128")] { self.0 } #[cfg(not(feature = "u128"))] { self.0 as u128 } } /// Retrieve the bit represented by this `Bit` instance. When the `u128` feature is enabled, if the bit is actually greater than **264 - 1**, it will return **264 - 1**. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let bit = Bit::parse_str("1kb").unwrap(); /// /// let result = bit.as_u64(); /// /// assert_eq!(1000, result); /// ``` /// /// ``` /// # #[cfg(feature = "u128")] /// # { /// use byte_unit::Bit; /// /// let bit = Bit::parse_str("1zb").unwrap(); /// /// let result = bit.as_u64(); /// /// assert_eq!(u64::MAX, result); /// # } /// ``` #[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 } } /// Retrieve the bit represented by this `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let bit = Bit::parse_str("1k").unwrap(); /// /// let result = bit.as_u64_checked(); /// /// assert_eq!(Some(1000), result); /// ``` /// /// ``` /// # #[cfg(feature = "u128")] /// # { /// use byte_unit::Bit; /// /// let bit = Bit::parse_str("1zb").unwrap(); /// /// let result = bit.as_u64_checked(); /// /// assert_eq!(None, result); /// # } /// ``` #[inline] pub const fn as_u64_checked(self) -> Option { #[cfg(feature = "u128")] { if self.0 <= u64::MAX as u128 { Some(self.0 as u64) } else { None } } #[cfg(not(feature = "u128"))] { Some(self.0) } } } /// Methods for calculation. impl Bit { /// Add another `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let bit_1 = Bit::from_u64(1024); /// let bit_2 = Bit::from_u64(512); /// /// let bit = bit_1.add(bit_2).unwrap(); /// /// assert_eq!(1536, bit.as_u64()); /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large, this function will return `None`. #[inline] pub const fn add(self, rhs: Bit) -> Option { match self.0.checked_add(rhs.0) { Some(v) => Some(Bit(v)), None => None, } } /// Subtract another `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let bit_1 = Bit::from_u64(1024); /// let bit_2 = Bit::from_u64(512); /// /// let bit = bit_1.subtract(bit_2).unwrap(); /// /// assert_eq!(512, bit.as_u64()); /// ``` /// /// # Points to Note /// /// * If the right-hand side is bigger then this `Bit` instance, this function will return `None`. #[inline] pub const fn subtract(self, rhs: Bit) -> Option { match self.0.checked_sub(rhs.0) { Some(v) => Some(Bit(v)), None => None, } } /// Multiplied by an unsigned integer. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let count = 100; /// let bit = Bit::from_u64(1024); /// /// let total_bit = bit.multiply(100).unwrap(); /// /// assert_eq!(102400, total_bit.as_u64()); /// ``` /// /// # Points to Note /// /// * If the calculated bit is too large, this function will return `None`. #[inline] pub const fn multiply(self, rhs: usize) -> Option { #[cfg(feature = "u128")] { match self.0.checked_mul(rhs as u128) { Some(v) => Some(Bit(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(Bit(v)), None => None, } } } /// Divided by an unsigned integer. /// /// # Examples /// /// ``` /// use byte_unit::Bit; /// /// let count = 100; /// let bit = Bit::from_u64(1024); /// /// let total_bit = bit.divide(100).unwrap(); /// /// assert_eq!(10, total_bit.as_u64()); /// ``` /// /// # Points to Note /// /// * If the input right-hand side is zero, this function will return `None`. /// * The result will be rounded down. #[inline] pub const fn divide(self, rhs: usize) -> Option { #[cfg(feature = "u128")] { match self.0.checked_div(rhs as u128) { Some(v) => Some(Bit(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(Bit(v)), None => None, } } } #[inline] pub(crate) const fn mul_8(self) -> Bit { Bit(self.0 * 8) } } /// Methods for finding an unit. impl Bit { /// Obtain the largest unit which is the greatest factor of this `Bit` instance. /// /// # Examples /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64(3145728); /// /// let (n, unit) = bit.get_exact_unit(true); /// /// assert_eq!(3, n); /// assert_eq!(Unit::Mibit, unit); /// ``` /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64(24000000); /// /// let (n, unit) = bit.get_exact_unit(true); /// /// assert_eq!(3, n); /// assert_eq!(Unit::MB, unit); /// ``` /// /// ``` /// use byte_unit::{Bit, Unit}; /// /// let bit = Bit::from_u64(24000000); /// /// let (n, unit) = bit.get_exact_unit(false); /// /// assert_eq!(24, n); /// assert_eq!(Unit::Mbit, unit); /// ``` #[inline] pub const fn get_exact_unit(self, allow_in_bytes: bool) -> (u128, Unit) { let bits_v = self.as_u128(); let a = if allow_in_bytes { Unit::get_multiples() } else { Unit::get_multiples_bits() }; let mut i = a.len() - 1; loop { let unit = a[i]; let unit_v = unit.as_bits_u128(); if bits_v >= unit_v && bits_v % unit_v == 0 { return (bits_v / unit_v, unit); } if i == 0 { break; } i -= 1; } (bits_v, Unit::Bit) } } byte-unit-5.1.4/src/bit/parse.rs000064400000000000000000000113711046102023000146030ustar 00000000000000use rust_decimal::prelude::*; use super::Bit; use crate::{common::get_char_from_bytes, unit::parse::read_xib, ParseError, ValueParseError}; /// Associated functions for parsing strings. impl Bit { /// Create a new `Bit` instance from a string. /// The string may be `"10"`, `"10B"`, `"10M"`, `"10MB"`, `"10MiB"`, `"80b"`, `"80Mb"`, `"80Mbit"`. /// /// You can ignore the case of **"B"** (bit), which means **b** will still be treated as bits instead of bits. /// /// # Examples /// /// ``` /// # use byte_unit::Bit; /// let bit = Bit::parse_str("123Kib").unwrap(); // 123 * 1024 bits /// ``` pub fn parse_str>(s: S) -> Result { let s = s.as_ref().trim(); let mut bits = s.bytes(); let mut value = match bits.next() { Some(e) => match e { b'0'..=b'9' => Decimal::from(e - b'0'), _ => { return Err(ValueParseError::NotNumber(unsafe { get_char_from_bytes(e, bits) }) .into()); }, }, None => return Err(ValueParseError::NoValue.into()), }; let e = 'outer: loop { match bits.next() { Some(e) => match e { b'0'..=b'9' => { value = value .checked_mul(Decimal::TEN) .ok_or(ValueParseError::NumberTooLong)? .checked_add(Decimal::from(e - b'0')) .ok_or(ValueParseError::NumberTooLong)?; }, b'.' => { let mut i = 1u32; loop { match bits.next() { Some(e) => match e { b'0'..=b'9' => { value += { let mut d = Decimal::from(e - b'0'); d.set_scale(i) .map_err(|_| ValueParseError::NumberTooLong)?; d }; i += 1; }, _ => { if i == 1 { return Err(ValueParseError::NotNumber(unsafe { get_char_from_bytes(e, bits) }) .into()); } match e { b' ' => loop { match bits.next() { Some(e) => match e { b' ' => (), _ => break 'outer Some(e), }, None => break 'outer None, } }, _ => break 'outer Some(e), } }, }, None => { if i == 1 { return Err(ValueParseError::NotNumber(unsafe { get_char_from_bytes(e, bits) }) .into()); } break 'outer None; }, } } }, b' ' => loop { match bits.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, bits, false, false)?; Self::from_decimal_with_unit(value, unit) .ok_or_else(|| ValueParseError::ExceededBounds(value).into()) } } byte-unit-5.1.4/src/bit/rocket_traits.rs000064400000000000000000000010021046102023000163340ustar 00000000000000use std::str::FromStr; use rocket::{ form::{self, FromFormField, ValueField}, request::FromParam, }; use super::Bit; use crate::ParseError; impl<'r> FromParam<'r> for Bit { type Error = ParseError; #[inline] fn from_param(v: &'r str) -> Result { Self::from_str(v) } } impl<'r> FromFormField<'r> for Bit { #[inline] fn from_value(v: ValueField<'r>) -> form::Result<'r, Self> { Ok(Self::from_str(v.value).map_err(form::Error::custom)?) } } byte-unit-5.1.4/src/bit/serde_traits.rs000064400000000000000000000042471046102023000161650ustar 00000000000000use core::{ fmt::{self, Formatter}, str::FromStr, }; use serde::{ self, de::{Error as DeError, Unexpected, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use super::Bit; #[cfg(feature = "u128")] use super::RONNABIT; impl Serialize for Bit { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { serializer.serialize_str(format!("{self:#}").as_str()) } else { serializer.serialize_u128(self.as_u128()) } } } impl<'de> Deserialize<'de> for Bit { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct MyVisitor; impl<'de> Visitor<'de> for MyVisitor { type Value = Bit; #[inline] fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a string such as \"123\", \"123Kib\", \"50.84 Mb\", or ")?; #[cfg(feature = "u128")] { f.write_fmt(format_args!("a positive integer smaller than {RONNABIT}")) } #[cfg(not(feature = "u128"))] { f.write_fmt(format_args!( "a positive integer smaller than {}", u64::MAX as u128 + 1 )) } } #[inline] fn visit_u128(self, v: u128) -> Result where E: DeError, { Bit::from_u128(v).ok_or_else(|| { DeError::invalid_value(Unexpected::Other(format!("{v}").as_str()), &self) }) } #[inline] fn visit_str(self, v: &str) -> Result where E: DeError, { Bit::from_str(v).map_err(DeError::custom) } } if deserializer.is_human_readable() { deserializer.deserialize_str(MyVisitor) } else { deserializer.deserialize_u128(MyVisitor) } } } byte-unit-5.1.4/src/byte/adjusted/built_in_traits.rs000064400000000000000000000022631046102023000206540ustar 00000000000000use core::str::FromStr; use super::{AdjustedByte, Byte, Unit, UnitType}; use crate::ParseError; impl From for AdjustedByte { /// `unit_type` is set to `UnitType::Both`. See [`Byte::get_appropriate_unit`](./struct.Byte.html#method.get_appropriate_unit). #[inline] fn from(value: Byte) -> Self { value.get_appropriate_unit(UnitType::Both) } } impl From for f64 { #[inline] fn from(value: AdjustedByte) -> Self { value.get_value() } } impl From for Unit { #[inline] fn from(value: AdjustedByte) -> Self { value.get_unit() } } impl From for Byte { #[inline] fn from(value: AdjustedByte) -> Self { value.get_byte() } } impl FromStr for AdjustedByte { type Err = ParseError; /// * `ignore_case` is set to `false`. See [`Byte::parse_str`](./struct.Byte.html#method.parse_str). /// * `unit_type` is set to `UnitType::Both`. See [`Byte::get_appropriate_unit`](./struct.Byte.html#method.get_appropriate_unit). #[inline] fn from_str(s: &str) -> Result { Ok(Byte::parse_str(s, false)?.get_appropriate_unit(UnitType::Both)) } } byte-unit-5.1.4/src/byte/adjusted/mod.rs000064400000000000000000000226561046102023000162500ustar 00000000000000mod built_in_traits; #[cfg(feature = "rocket")] mod rocket_traits; #[cfg(feature = "serde")] mod serde_traits; use core::{ cmp::Ordering, fmt::{self, Alignment, Display, Formatter, Write}, }; use super::{Byte, Unit}; use crate::{common::round_fractional_part_f64, UnitType}; /// Generated from the [`Byte::get_adjusted_unit`](./struct.Byte.html#method.get_adjusted_unit) method or the the [`Byte::get_appropriate_unit`](./struct.Byte.html#method.get_appropriate_unit) method. /// /// For accuracy representation, utilize the `Byte` struct. #[derive(Debug, Clone, Copy)] pub struct AdjustedByte { pub(crate) value: f64, pub(crate) unit: Unit, } impl PartialEq for AdjustedByte { #[inline] fn eq(&self, other: &AdjustedByte) -> bool { let s = self.get_byte(); let o = other.get_byte(); s.eq(&o) } } impl Eq for AdjustedByte {} impl PartialOrd for AdjustedByte { #[inline] fn partial_cmp(&self, other: &AdjustedByte) -> Option { Some(self.cmp(other)) } } impl Ord for AdjustedByte { #[inline] fn cmp(&self, other: &AdjustedByte) -> Ordering { let s = self.get_byte(); let o = other.get_byte(); s.cmp(&o) } } impl Display for AdjustedByte { /// Formats the value using the given formatter. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64_with_unit(1555, Unit::KB).unwrap(); /// /// let adjusted_byte = byte.get_adjusted_unit(Unit::MB); /// /// assert_eq!("1.555 MB", adjusted_byte.to_string()); /// ``` /// /// ``` /// use byte_unit::{Byte, UnitType}; /// /// let byte = Byte::from_u64(10000); /// /// let adjusted_byte_based_2 = byte.get_appropriate_unit(UnitType::Binary); /// let adjusted_byte_based_10 = byte.get_appropriate_unit(UnitType::Decimal); /// /// assert_eq!("9.765625 KiB", format!("{adjusted_byte_based_2}")); /// assert_eq!("10 KB", format!("{adjusted_byte_based_10}")); /// /// // with precision /// assert_eq!("9.77 KiB", format!("{adjusted_byte_based_2:.2}")); /// assert_eq!("10.00 KB", format!("{adjusted_byte_based_10:.2}")); /// /// // without any unnecessary fractional part /// assert_eq!("9.77 KiB", format!("{adjusted_byte_based_2:#.2}")); /// assert_eq!("10 KB", format!("{adjusted_byte_based_10:#.2}")); /// /// // with a width, left alignment /// assert_eq!("9.77 KiB", format!("{adjusted_byte_based_2:10.2}")); /// assert_eq!("10.00 KB", format!("{adjusted_byte_based_10:10.2}")); /// /// // with a width, right alignment /// assert_eq!(" 9.77 KiB", format!("{adjusted_byte_based_2:>10.2}")); /// assert_eq!(" 10.00 KB", format!("{adjusted_byte_based_10:>10.2}")); /// /// // with a width, right alignment, more spaces between the value and the unit /// assert_eq!(" 9.77 KiB", format!("{adjusted_byte_based_2:>+10.2}")); /// assert_eq!(" 10.00 KB", format!("{adjusted_byte_based_10:>+10.2}")); /// /// // no spaces between the value and the unit /// assert_eq!("9.765625KiB", format!("{adjusted_byte_based_2:-}")); /// assert_eq!("10KB", format!("{adjusted_byte_based_10:-}")); /// ``` fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let Self { value, unit, } = self; let handle_basic_precision = |precision: usize, f: &mut Formatter<'_>| -> fmt::Result { if f.alternate() { let value = round_fractional_part_f64(*value, precision); f.write_fmt(format_args!("{value}")) } else if matches!(unit, Unit::Bit | Unit::B) { f.write_fmt(format_args!("{value}")) } else { f.write_fmt(format_args!("{value:.precision$}")) } }; 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 let Some(precision) = f.precision() { if width > l + 1 { width -= l; let alignment = f.align().unwrap_or(Alignment::Left); if f.alternate() { let value = round_fractional_part_f64(*value, precision); match alignment { Alignment::Left | Alignment::Center => { f.write_fmt(format_args!("{value: f.write_fmt(format_args!("{value:>width$}"))?, } } else { match alignment { Alignment::Left | Alignment::Center => { f.write_fmt(format_args!("{value: { f.write_fmt(format_args!("{value:>width$.precision$}"))? }, } } } else { handle_basic_precision(precision, f)?; } } else 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: f.write_fmt(format_args!("{value:>width$}"))?, } } else { f.write_fmt(format_args!("{value}"))?; } } else if let Some(precision) = f.precision() { handle_basic_precision(precision, f)?; } else { f.write_fmt(format_args!("{value}"))?; } for _ in 0..space_length { f.write_char(' ')?; } f.write_fmt(format_args!("{unit}")) } } /// Methods for getting values. impl AdjustedByte { /// Get the value. #[inline] pub const fn get_value(&self) -> f64 { self.value } /// Get the unit. #[inline] pub const fn get_unit(&self) -> Unit { self.unit } /// Create a new `Byte` instance from this `AdjustedByte` instance. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64_with_unit(1555, Unit::KB).unwrap(); /// /// let adjusted_byte = byte.get_adjusted_unit(Unit::MB); /// /// let byte_back = adjusted_byte.get_byte(); /// /// assert_eq!(byte, byte_back); /// ``` /// /// # Points to Note /// /// * The result may not be logically equal to the original `Byte` instance due to the accuracy of floating-point numbers. #[inline] pub fn get_byte(&self) -> Byte { Byte::from_f64_with_unit(self.value, self.unit).unwrap() } } /// Associated functions for generating `AdjustedByte`. impl Byte { /// Adjust the unit and value for this `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::{AdjustedByte, Byte, Unit}; /// /// let byte = Byte::parse_str("123KiB", true).unwrap(); /// /// let adjusted_byte = byte.get_adjusted_unit(Unit::KB); /// /// assert_eq!("125.952 KB", adjusted_byte.to_string()); /// ``` /// /// ``` /// use byte_unit::{AdjustedByte, Byte, Unit}; /// /// let byte = Byte::parse_str("50.84 MB", true).unwrap(); /// /// let adjusted_byte = byte.get_adjusted_unit(Unit::MiB); /// /// assert_eq!("48.48480224609375 MiB", adjusted_byte.to_string()); /// ``` #[inline] pub fn get_adjusted_unit(self, unit: Unit) -> AdjustedByte { let byte_v = self.as_u128(); let value = match unit { Unit::Bit => (byte_v << 3) as f64, Unit::B => byte_v as f64, _ => byte_v as f64 / unit.as_bytes_u128() as f64, }; AdjustedByte { value, unit, } } /// Find the appropriate unit and value for this `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, UnitType}; /// /// let byte = Byte::parse_str("123KiB", true).unwrap(); /// /// let adjusted_byte = byte.get_appropriate_unit(UnitType::Decimal); /// /// assert_eq!("125.952 KB", adjusted_byte.to_string()); /// ``` /// /// ``` /// use byte_unit::{Byte, UnitType}; /// /// let byte = Byte::parse_str("50.84 MB", true).unwrap(); /// /// let adjusted_byte = byte.get_appropriate_unit(UnitType::Binary); /// /// assert_eq!("48.48480224609375 MiB", adjusted_byte.to_string()); /// ``` pub fn get_appropriate_unit(&self, unit_type: UnitType) -> AdjustedByte { let a = Unit::get_multiples_bytes(); let (skip, step) = match unit_type { UnitType::Binary => (0, 2), UnitType::Decimal => (1, 2), UnitType::Both => (0, 1), }; let bytes_v = self.as_u128(); for unit in a.iter().rev().skip(skip).step_by(step) { if bytes_v >= unit.as_bytes_u128() { return self.get_adjusted_unit(*unit); } } self.get_adjusted_unit(Unit::B) } } byte-unit-5.1.4/src/byte/adjusted/rocket_traits.rs000064400000000000000000000010351046102023000203320ustar 00000000000000use std::str::FromStr; use rocket::{ form::{self, FromFormField, ValueField}, request::FromParam, }; use super::AdjustedByte; use crate::ParseError; impl<'r> FromParam<'r> for AdjustedByte { type Error = ParseError; #[inline] fn from_param(v: &'r str) -> Result { Self::from_str(v) } } impl<'r> FromFormField<'r> for AdjustedByte { #[inline] fn from_value(v: ValueField<'r>) -> form::Result<'r, Self> { Ok(Self::from_str(v.value).map_err(form::Error::custom)?) } } byte-unit-5.1.4/src/byte/adjusted/serde_traits.rs000064400000000000000000000024701046102023000201510ustar 00000000000000use core::{ fmt::{self, Formatter}, str::FromStr, }; use serde::{ self, de::{Error as DeError, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use super::AdjustedByte; impl Serialize for AdjustedByte { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { serializer.serialize_str(format!("{:#}", self).as_str()) } else { serializer.serialize_str(format!("{:-#}", self).as_str()) } } } impl<'de> Deserialize<'de> for AdjustedByte { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct MyVisitor; impl<'de> Visitor<'de> for MyVisitor { type Value = AdjustedByte; #[inline] fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a string such as \"123\", \"123KiB\", \"50.84 MB\"") } #[inline] fn visit_str(self, v: &str) -> Result where E: DeError, { AdjustedByte::from_str(v).map_err(DeError::custom) } } deserializer.deserialize_str(MyVisitor) } } byte-unit-5.1.4/src/byte/built_in_traits.rs000064400000000000000000000153531046102023000170550ustar 00000000000000use core::{cmp::Ordering, str::FromStr}; use super::Byte; use crate::{ExceededBoundsError, ParseError, TryFromIntError}; impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: u128) -> Result { Byte::from_u128(value).ok_or(ExceededBoundsError) } } impl From for Byte { #[inline] fn from(value: u64) -> Self { Byte::from_u64(value) } } impl From for Byte { #[inline] fn from(value: u32) -> Self { Byte::from_u64(value as u64) } } impl From for Byte { #[inline] fn from(value: u16) -> Self { Byte::from_u64(value as u64) } } impl From for Byte { #[inline] fn from(value: u8) -> Self { Byte::from_u64(value as u64) } } impl From for Byte { #[inline] fn from(value: usize) -> Self { #[cfg(target_pointer_width = "128")] { Byte::from_u128(value as u128).unwrap_or(Byte::MAX) } #[cfg(not(target_pointer_width = "128"))] { Byte::from_u64(value as u64) } } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: i128) -> Result { Byte::from_i128(value).ok_or(ExceededBoundsError) } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: i64) -> Result { Byte::from_i64(value).ok_or(ExceededBoundsError) } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: i32) -> Result { Byte::from_i64(value as i64).ok_or(ExceededBoundsError) } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: i16) -> Result { Byte::from_i64(value as i64).ok_or(ExceededBoundsError) } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: i8) -> Result { Byte::from_i64(value as i64).ok_or(ExceededBoundsError) } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: isize) -> Result { #[cfg(target_pointer_width = "128")] { Byte::from_i128(value as i128).ok_or(ExceededBoundsError) } #[cfg(not(target_pointer_width = "128"))] { Byte::from_i64(value as i64).ok_or(ExceededBoundsError) } } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: f64) -> Result { Byte::from_f64(value).ok_or(ExceededBoundsError) } } impl TryFrom for Byte { type Error = ExceededBoundsError; #[inline] fn try_from(value: f32) -> Result { Byte::from_f32(value).ok_or(ExceededBoundsError) } } impl From for u128 { #[inline] fn from(byte: Byte) -> Self { byte.as_u128() } } impl From for u64 { #[inline] fn from(byte: Byte) -> Self { byte.as_u64() } } impl TryFrom for u32 { type Error = TryFromIntError; #[inline] fn try_from(byte: Byte) -> Result { u32::try_from(byte.as_u64()) } } impl TryFrom for u16 { type Error = TryFromIntError; #[inline] fn try_from(byte: Byte) -> Result { u16::try_from(byte.as_u64()) } } impl TryFrom for u8 { type Error = TryFromIntError; #[inline] fn try_from(byte: Byte) -> Result { u8::try_from(byte.as_u64()) } } impl TryFrom for usize { type Error = TryFromIntError; #[inline] fn try_from(byte: Byte) -> Result { #[cfg(target_pointer_width = "128")] { usize::try_from(byte.as_u128()) } #[cfg(not(target_pointer_width = "128"))] { usize::try_from(byte.as_u64()) } } } impl FromStr for Byte { type Err = ParseError; /// `ignore_case` is set to `false`. See [`Byte::parse_str`](#method.parse_str). #[inline] fn from_str(s: &str) -> Result { Byte::parse_str(s, false) } } impl PartialEq for Byte { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &u64) -> bool { self.0 == *other as u128 } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &u64) -> bool { self.0 == *other } } impl PartialEq for Byte { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &u128) -> bool { self.0 == *other } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &u128) -> bool { self.0 as u128 == *other } } impl PartialEq for u64 { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &Byte) -> bool { *self as u128 == other.0 } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &Byte) -> bool { *self == other.0 } } impl PartialEq for u128 { #[cfg(feature = "u128")] #[inline] fn eq(&self, other: &Byte) -> bool { *self == other.0 } #[cfg(not(feature = "u128"))] #[inline] fn eq(&self, other: &Byte) -> bool { *self == other.0 as u128 } } impl PartialOrd for Byte { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &u64) -> Option { self.0.partial_cmp(&(*other as u128)) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &u64) -> Option { self.0.partial_cmp(other) } } impl PartialOrd for Byte { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &u128) -> Option { self.0.partial_cmp(other) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &u128) -> Option { (self.0 as u128).partial_cmp(other) } } impl PartialOrd for u64 { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &Byte) -> Option { (*self as u128).partial_cmp(&other.0) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &Byte) -> Option { self.partial_cmp(&other.0) } } impl PartialOrd for u128 { #[cfg(feature = "u128")] #[inline] fn partial_cmp(&self, other: &Byte) -> Option { self.partial_cmp(&other.0) } #[cfg(not(feature = "u128"))] #[inline] fn partial_cmp(&self, other: &Byte) -> Option { self.partial_cmp(&(other.0 as u128)) } } byte-unit-5.1.4/src/byte/constants.rs000064400000000000000000000072431046102023000156750ustar 00000000000000use super::Byte; #[cfg(feature = "u128")] use super::RONNABYTE; /// Constant `Byte`s. #[rustfmt::skip] impl Byte { /// One byte. pub const BYTE: Byte = Byte(1); /// 1 KB = 103 bytes. pub const KILOBYTE: Byte = Byte(1_000); /// 1 MB = 106 bytes. pub const MEGABYTE: Byte = Byte(1_000_000); /// 1 GB = 109 bytes. pub const GIGABYTE: Byte = Byte(1_000_000_000); /// 1 TB = 1012 bytes. pub const TERABYTE: Byte = Byte(1_000_000_000_000); /// 1 PB = 1015 bytes. pub const PETABYTE: Byte = Byte(1_000_000_000_000_000); /// 1 EB = 1018 bytes. pub const EXABYTE: Byte = Byte(1_000_000_000_000_000_000); #[cfg(feature = "u128")] /// 1 ZB = 1021 bytes. pub const ZETTABYTE: Byte = Byte(1_000_000_000_000_000_000_000); #[cfg(feature = "u128")] /// 1 YB = 1024 bytes. pub const YOTTABYTE: Byte = Byte(1_000_000_000_000_000_000_000_000); /// 1 KiB = 210 bytes. pub const KIBIBYTE: Byte = Byte(1 << 10); /// 1 MiB = 220 bytes. pub const MEBIBYTE: Byte = Byte(1 << 20); /// 1 GiB = 230 bytes. pub const GIBIBYTE: Byte = Byte(1 << 30); /// 1 TiB = 240 bytes. pub const TEBIBYTE: Byte = Byte(1 << 40); /// 1 PiB = 250 bytes. pub const PEBIBYTE: Byte = Byte(1 << 50); /// 1 EiB = 260 bytes. pub const EXBIBYTE: Byte = Byte(1 << 60); #[cfg(feature = "u128")] /// 1 ZiB = 270 bytes. pub const ZEBIBYTE: Byte = Byte(1 << 70); #[cfg(feature = "u128")] /// 1 YiB = 280 bytes. pub const YOBIBYTE: Byte = Byte(1 << 80); /// 1 Kbit = 125 bytes. pub const KILOBIT: Byte = Byte::KILOBYTE.div_8(); /// 1 Mbit = 125 * 103 bytes. pub const MEGABIT: Byte = Byte::MEGABYTE.div_8(); /// 1 Gbit = 125 * 106 bytes. pub const GIGABIT: Byte = Byte::GIGABYTE.div_8(); /// 1 Tbit = 125 * 109 bytes. pub const TERABIT: Byte = Byte::TERABYTE.div_8(); /// 1 Pbit = 125 * 1012 bytes. pub const PETABIT: Byte = Byte::PETABYTE.div_8(); /// 1 Ebit = 125 * 1015 bytes. pub const EXABIT: Byte = Byte::EXABYTE.div_8(); #[cfg(feature = "u128")] /// 1 Zbit = 125 * 1018 bytes. pub const ZETTABIT: Byte = Byte::ZETTABYTE.div_8(); #[cfg(feature = "u128")] /// 1 Ybit = 125 * 1021 bytes. pub const YOTTABIT: Byte = Byte::YOTTABYTE.div_8(); /// 1 Kibit = 27 bytes. pub const KIBIBIT: Byte = Byte::KIBIBYTE.div_8(); /// 1 Mibit = 217 bytes. pub const MEBIBIT: Byte = Byte::MEBIBYTE.div_8(); /// 1 Gibit = 227 bytes. pub const GIBIBIT: Byte = Byte::GIBIBYTE.div_8(); /// 1 Tibit = 237 bytes. pub const TEBIBIT: Byte = Byte::TEBIBYTE.div_8(); /// 1 Pibit = 247 bytes. pub const PEBIBIT: Byte = Byte::PEBIBYTE.div_8(); /// 1 Eibit = 257 bytes. pub const EXBIBIT: Byte = Byte::EXBIBYTE.div_8(); #[cfg(feature = "u128")] /// 1 Zibit = 267 bytes. pub const ZEBIBIT: Byte = Byte::ZEBIBYTE.div_8(); #[cfg(feature = "u128")] /// 1 Yibit = 277 bytes. pub const YOBIBIT: Byte = Byte::YOBIBYTE.div_8(); /// 0 byte. pub const MIN: Byte = Byte(0); /// **1027 - 1** bytes if the `u128` feature is enabled, or **264 - 1** otherwise. pub const MAX: Byte = { #[cfg(feature = "u128")] { Byte(RONNABYTE - 1) } #[cfg(not(feature = "u128"))] { Byte(u64::MAX) } }; } byte-unit-5.1.4/src/byte/decimal.rs000064400000000000000000000107471046102023000152620ustar 00000000000000use 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); /// Associated functions for building `Byte` instances using `Decimal`. impl Byte { /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// use rust_decimal::Decimal; /// /// let byte = Byte::from_decimal(Decimal::from(15000000u64)).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or not greater than or equal to **0**, this function will return `None`. /// * The fractional part will be rounded up. #[inline] pub fn from_decimal(size: Decimal) -> Option { 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 } } } /// Associated functions for building `Byte` instances using `Decimal` (with `Unit`). impl Byte { /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// use rust_decimal::Decimal; /// /// let byte = Byte::from_decimal_with_unit(Decimal::from(15u64), Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large or not greater than or equal to **0**, this function will return `None`. /// * The calculated byte will be rounded up. #[inline] pub fn from_decimal_with_unit(size: Decimal, unit: Unit) -> Option { let v = { match unit { Unit::Bit => (size / DECIMAL_EIGHT).ceil(), Unit::B => size, _ => match size.checked_mul(Decimal::from(unit.as_bytes_u128())) { Some(v) => v, None => return None, }, } }; Self::from_decimal(v) } } /// Methods for finding an unit using `Decimal`. impl Byte { /// Find the appropriate unit and value that can be used to recover back to this `Byte` precisely. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64(3670016); /// /// assert_eq!( /// (3.5f64.try_into().unwrap(), Unit::MiB), /// byte.get_recoverable_unit(false, 3) /// ); /// ``` /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64(437500); /// /// assert_eq!( /// (3.5f64.try_into().unwrap(), Unit::Mbit), /// byte.get_recoverable_unit(true, 3) /// ); /// ``` /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64(437500); /// /// assert_eq!( /// (437.5f64.try_into().unwrap(), Unit::KB), /// byte.get_recoverable_unit(false, 3) /// ); /// ``` /// /// # Points to Note /// /// * `precision` should be smaller or equal to `26` if the `u128` feature is enabled, otherwise `19`. The typical `precision` is `3`. #[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) } } byte-unit-5.1.4/src/byte/mod.rs000064400000000000000000000551341046102023000144420ustar 00000000000000mod adjusted; mod built_in_traits; mod constants; mod decimal; mod parse; #[cfg(feature = "rocket")] mod rocket_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; // RB #[cfg(feature = "u128")] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] /// Representing the size in bytes. pub struct Byte(u128); #[cfg(not(feature = "u128"))] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] /// Representing the size in bytes. pub struct Byte(u64); impl Display for Byte { /// Formats the value using the given formatter. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64_with_unit(1555, Unit::KB).unwrap(); /// /// assert_eq!("1555000", byte.to_string()); /// ``` /// /// ``` /// use byte_unit::{Byte, UnitType}; /// /// let byte_based_2 = Byte::from_u64(10240); /// let byte_based_10 = Byte::from_u64(10000); /// /// assert_eq!("10240", format!("{byte_based_2}")); /// assert_eq!("10000", format!("{byte_based_10}")); /// /// // with an exact unit /// assert_eq!("10 KiB", format!("{byte_based_2:#}")); /// assert_eq!("10 KB", format!("{byte_based_10:#}")); /// /// // with an exact unit, no spaces between the value and the unit /// assert_eq!("10KiB", format!("{byte_based_2:-#}")); /// assert_eq!("10KB", format!("{byte_based_10:-#}")); /// /// // with a width, left alignment /// assert_eq!("10 KiB", format!("{byte_based_2:#10}")); /// assert_eq!("10 KB", format!("{byte_based_10:#10}")); /// /// // with a width, right alignment /// assert_eq!(" 10 KiB", format!("{byte_based_2:>#10}")); /// assert_eq!(" 10 KB", format!("{byte_based_10:>#10}")); /// /// // with a width, right alignment, more spaces between the value and the unit /// assert_eq!(" 10 KiB", format!("{byte_based_2:>+#10}")); /// assert_eq!(" 10 KB", format!("{byte_based_10:>+#10}")); /// ``` /// /// ``` /// use byte_unit::{Byte, UnitType}; /// /// let byte = Byte::from_u64(3211776); /// /// assert_eq!("3211776", format!("{byte}")); /// /// // with a unit, still precisely /// assert_eq!("3136.5 KiB", format!("{byte:#}")); /// /// // with a unit and a larger precision (default is 3), still precisely /// assert_eq!("3.211776 MB", format!("{byte:#.6}")); /// /// // with a unit and a smaller precision (default is 3), still precisely /// assert_eq!("3211776 B", format!("{byte:#.0}")); /// ``` 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: 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) } } } /// Associated functions for building `Byte` instances. impl Byte { /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::from_u128(15000000).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise), this function will return `None`. #[inline] pub const fn from_u128(size: u128) -> Option { #[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 } } } /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = unsafe { Byte::from_u128_unsafe(15000000) }; // 15 MB /// ``` /// /// # Safety /// You must ensure the input **size** is not too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) on your own. #[inline] pub const unsafe fn from_u128_unsafe(size: u128) -> Self { #[cfg(feature = "u128")] { Byte(size) } #[cfg(not(feature = "u128"))] { Byte(size as u64) } } /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::from_u64(15000000); // 15 MB /// ``` #[inline] pub const fn from_u64(size: u64) -> Self { #[cfg(feature = "u128")] { Byte(size as u128) } #[cfg(not(feature = "u128"))] { Byte(size) } } /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::from_f64(15000000.0).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or not greater than or equal to **0**, this function will return `None`. /// * The fractional part will be rounded up. #[inline] pub fn from_f64(size: f64) -> Option { 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 } } /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::from_f32(15000000.0).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or not greater than or equal to **0**, this function will return `None`. /// * The fractional part will be rounded up. #[inline] pub fn from_f32(size: f32) -> Option { 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 } } /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::from_i128(15000000).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the input **size** is too large (the maximum is **1027 - 1** if the `u128` feature is enabled, or **264 - 1** otherwise) or negative, this function will return `None`. #[inline] pub const fn from_i128(size: i128) -> Option { if size >= 0 { Self::from_u128(size as u128) } else { None } } /// Create a new `Byte` instance from a size in bytes. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::from_i64(15000000).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the input **size** is negative, this function will return `None`. #[inline] pub const fn from_i64(size: i64) -> Option { if size >= 0 { Some(Self::from_u64(size as u64)) } else { None } } } /// Associated functions for building `Byte` instances (with `Unit`). impl Byte { /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u128_with_unit(15, Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large, this function will return `None`. /// * If the input **unit** is `Bit`, the calculated byte will be rounded up. #[inline] pub const fn from_u128_with_unit(size: u128, unit: Unit) -> Option { 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) } /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64_with_unit(15, Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large, this function will return `None`. /// * If the input **unit** is `Bit`, the calculated byte will be rounded up. #[inline] pub const fn from_u64_with_unit(size: u64, unit: Unit) -> Option { #[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)) } } /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_f64_with_unit(15.0, Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large or not greater than or equal to **0**, this function will return `None`. /// * The calculated byte will be rounded up. #[inline] pub fn from_f64_with_unit(size: f64, unit: Unit) -> Option { match Decimal::from_f64(size) { Some(size) => Self::from_decimal_with_unit(size, unit), None => None, } } /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_f32_with_unit(15.0, Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large or not greater than or equal to **0**, this function will return `None`. /// * The calculated byte will be rounded up. #[inline] pub fn from_f32_with_unit(size: f32, unit: Unit) -> Option { match Decimal::from_f32(size) { Some(size) => Self::from_decimal_with_unit(size, unit), None => None, } } /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_i128_with_unit(15, Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large or negative, this function will return `None`. /// * The calculated byte will be rounded up. #[inline] pub const fn from_i128_with_unit(size: i128, unit: Unit) -> Option { if size >= 0 { Self::from_u128_with_unit(size as u128, unit) } else { None } } /// Create a new `Byte` instance from a size of bytes with a unit. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_i64_with_unit(15, Unit::MB).unwrap(); // 15 MB /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large or negative, this function will return `None`. /// * The calculated byte will be rounded up. #[inline] pub const fn from_i64_with_unit(size: i64, unit: Unit) -> Option { if size >= 0 { Self::from_u64_with_unit(size as u64, unit) } else { None } } } /// Methods for converting a `Byte` instance into a primitive integer. impl Byte { /// Retrieve the byte represented by this `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let byte = Byte::parse_str("123Kib", true).unwrap(); /// /// let result = byte.as_u128(); /// /// assert_eq!(125952, result); /// ``` /// /// ``` /// use byte_unit::Byte; /// /// let byte = Byte::parse_str("123Kib", false).unwrap(); /// /// let result = byte.as_u128(); /// /// assert_eq!(15744, result); /// ``` #[inline] pub const fn as_u128(self) -> u128 { #[cfg(feature = "u128")] { self.0 } #[cfg(not(feature = "u128"))] { self.0 as u128 } } /// Retrieve the byte represented by this `Byte` instance. When the `u128` feature is enabled, if the byte is actually greater than **264 - 1**, it will return **264 - 1**. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let byte = Byte::parse_str("1kb", true).unwrap(); /// /// let result = byte.as_u64(); /// /// assert_eq!(1000, result); /// ``` /// /// ``` /// # #[cfg(feature = "u128")] /// # { /// use byte_unit::Byte; /// /// let byte = Byte::parse_str("1zb", true).unwrap(); /// /// let result = byte.as_u64(); /// /// assert_eq!(u64::MAX, result); /// # } /// ``` #[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 } } /// Retrieve the byte represented by this `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let byte = Byte::parse_str("1kb", true).unwrap(); /// /// let result = byte.as_u64_checked(); /// /// assert_eq!(Some(1000), result); /// ``` /// /// ``` /// # #[cfg(feature = "u128")] /// # { /// use byte_unit::Byte; /// /// let byte = Byte::parse_str("1zb", true).unwrap(); /// /// let result = byte.as_u64_checked(); /// /// assert_eq!(None, result); /// # } /// ``` #[inline] pub const fn as_u64_checked(self) -> Option { #[cfg(feature = "u128")] { if self.0 <= u64::MAX as u128 { Some(self.0 as u64) } else { None } } #[cfg(not(feature = "u128"))] { Some(self.0) } } } /// Methods for calculation. impl Byte { /// Add another `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let byte_1 = Byte::from_u64(1024); /// let byte_2 = Byte::from_u64(512); /// /// let byte = byte_1.add(byte_2).unwrap(); /// /// assert_eq!(1536, byte.as_u64()); /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large, this function will return `None`. #[inline] pub const fn add(self, rhs: Byte) -> Option { match self.0.checked_add(rhs.0) { Some(v) => Some(Byte(v)), None => None, } } /// Subtract another `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let byte_1 = Byte::from_u64(1024); /// let byte_2 = Byte::from_u64(512); /// /// let byte = byte_1.subtract(byte_2).unwrap(); /// /// assert_eq!(512, byte.as_u64()); /// ``` /// /// # Points to Note /// /// * If the right-hand side is bigger then this `Byte` instance, this function will return `None`. #[inline] pub const fn subtract(self, rhs: Byte) -> Option { match self.0.checked_sub(rhs.0) { Some(v) => Some(Byte(v)), None => None, } } /// Multiplied by an unsigned integer. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let count = 100; /// let byte = Byte::from_u64(1024); /// /// let total_byte = byte.multiply(100).unwrap(); /// /// assert_eq!(102400, total_byte.as_u64()); /// ``` /// /// # Points to Note /// /// * If the calculated byte is too large, this function will return `None`. #[inline] pub const fn multiply(self, rhs: usize) -> Option { #[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, } } } /// Divided by an unsigned integer. /// /// # Examples /// /// ``` /// use byte_unit::Byte; /// /// let count = 100; /// let byte = Byte::from_u64(1024); /// /// let total_byte = byte.divide(100).unwrap(); /// /// assert_eq!(10, total_byte.as_u64()); /// ``` /// /// # Points to Note /// /// * If the input right-hand side is zero, this function will return `None`. /// * The result will be rounded down. #[inline] pub const fn divide(self, rhs: usize) -> Option { #[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) } } /// Methods for finding an unit. impl Byte { /// Obtain the largest unit which is the greatest factor of this `Byte` instance. /// /// # Examples /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64(3145728); /// /// let (n, unit) = byte.get_exact_unit(true); /// /// assert_eq!(3, n); /// assert_eq!(Unit::MiB, unit); /// ``` /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64(375000); /// /// let (n, unit) = byte.get_exact_unit(true); /// /// assert_eq!(3, n); /// assert_eq!(Unit::Mbit, unit); /// ``` /// /// ``` /// use byte_unit::{Byte, Unit}; /// /// let byte = Byte::from_u64(375000); /// /// let (n, unit) = byte.get_exact_unit(false); /// /// assert_eq!(375, n); /// assert_eq!(Unit::KB, unit); /// ``` #[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) } } byte-unit-5.1.4/src/byte/parse.rs000064400000000000000000000117211046102023000147670ustar 00000000000000use rust_decimal::prelude::*; use super::Byte; use crate::{common::get_char_from_bytes, unit::parse::read_xib, ParseError, ValueParseError}; /// Associated functions for parsing strings. impl Byte { /// Create a new `Byte` instance from a string. /// The string may be `"10"`, `"10B"`, `"10M"`, `"10MB"`, `"10MiB"`, `"80b"`, `"80Mb"`, `"80Mbit"`. /// /// You can ignore the case of **"B"** (byte), which means **b** will still be treated as bytes instead of bits. /// /// # Examples /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::parse_str("123Kib", true).unwrap(); // 123 * 1024 bytes /// ``` /// /// ``` /// # use byte_unit::Byte; /// let byte = Byte::parse_str("123Kib", false).unwrap(); // 123 * 1024 bits = 123 * 1024 / 8 bytes /// ``` pub fn parse_str>(s: S, ignore_case: bool) -> Result { 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' => Decimal::from(e - b'0'), _ => { return Err(ValueParseError::NotNumber(unsafe { get_char_from_bytes(e, bytes) }) .into()); }, }, None => return Err(ValueParseError::NoValue.into()), }; let e = 'outer: loop { match bytes.next() { Some(e) => match e { b'0'..=b'9' => { value = value .checked_mul(Decimal::TEN) .ok_or(ValueParseError::NumberTooLong)? .checked_add(Decimal::from(e - b'0')) .ok_or(ValueParseError::NumberTooLong)?; }, b'.' => { let mut i = 1u32; loop { match bytes.next() { Some(e) => match e { b'0'..=b'9' => { value += { let mut d = Decimal::from(e - b'0'); d.set_scale(i) .map_err(|_| ValueParseError::NumberTooLong)?; d }; i += 1; }, _ => { if i == 1 { return Err(ValueParseError::NotNumber(unsafe { 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 == 1 { return Err(ValueParseError::NotNumber(unsafe { 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, ignore_case, true)?; Self::from_decimal_with_unit(value, unit) .ok_or_else(|| ValueParseError::ExceededBounds(value).into()) } } byte-unit-5.1.4/src/byte/rocket_traits.rs000064400000000000000000000010051046102023000165240ustar 00000000000000use std::str::FromStr; use rocket::{ form::{self, FromFormField, ValueField}, request::FromParam, }; use super::Byte; use crate::ParseError; impl<'r> FromParam<'r> for Byte { type Error = ParseError; #[inline] fn from_param(v: &'r str) -> Result { Self::from_str(v) } } impl<'r> FromFormField<'r> for Byte { #[inline] fn from_value(v: ValueField<'r>) -> form::Result<'r, Self> { Ok(Self::from_str(v.value).map_err(form::Error::custom)?) } } byte-unit-5.1.4/src/byte/serde_traits.rs000064400000000000000000000042571046102023000163530ustar 00000000000000use core::{ fmt::{self, Formatter}, str::FromStr, }; use serde::{ self, de::{Error as DeError, Unexpected, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use super::Byte; #[cfg(feature = "u128")] use super::RONNABYTE; impl Serialize for Byte { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { serializer.serialize_str(format!("{self:#}").as_str()) } else { serializer.serialize_u128(self.as_u128()) } } } impl<'de> Deserialize<'de> for Byte { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct MyVisitor; impl<'de> Visitor<'de> for MyVisitor { type Value = Byte; #[inline] fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a string such as \"123\", \"123KiB\", \"50.84 MB\", or ")?; #[cfg(feature = "u128")] { f.write_fmt(format_args!("a positive integer smaller than {RONNABYTE}")) } #[cfg(not(feature = "u128"))] { f.write_fmt(format_args!( "a positive integer smaller than {}", u64::MAX as u128 + 1 )) } } #[inline] fn visit_u128(self, v: u128) -> Result where E: DeError, { Byte::from_u128(v).ok_or_else(|| { DeError::invalid_value(Unexpected::Other(format!("{v}").as_str()), &self) }) } #[inline] fn visit_str(self, v: &str) -> Result where E: DeError, { Byte::from_str(v).map_err(DeError::custom) } } if deserializer.is_human_readable() { deserializer.deserialize_str(MyVisitor) } else { deserializer.deserialize_u128(MyVisitor) } } } byte-unit-5.1.4/src/common.rs000064400000000000000000000057321046102023000142070ustar 00000000000000use core::str::Bytes; #[cfg(any(feature = "byte", feature = "bit"))] use rust_decimal::prelude::*; /// # Safety /// Make sure the input is valid on your own. pub(crate) unsafe fn get_char_from_bytes(e: u8, mut bytes: Bytes) -> char { let width = utf8_width::get_width_assume_valid(e); let mut char_bytes = [0; 4]; char_bytes[0] = e; if width > 1 { for e in char_bytes[1..].iter_mut().take(width - 1) { *e = bytes.next().unwrap(); } } char::from_u32_unchecked(u32::from_ne_bytes(char_bytes)) } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] #[inline] pub(crate) fn ceil_f64(v: f64) -> f64 { v.ceil() } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(not(feature = "std"))] #[inline] pub(crate) fn ceil_f64(v: f64) -> f64 { debug_assert!(v >= 0.0); Decimal::from_f64(v).unwrap().ceil().to_f64().unwrap() } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] #[inline] pub(crate) fn ceil_f32(v: f32) -> f32 { debug_assert!(v >= 0.0); v.ceil() } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(not(feature = "std"))] #[inline] pub(crate) fn ceil_f32(v: f32) -> f32 { debug_assert!(v >= 0.0); Decimal::from_f32(v).unwrap().ceil().to_f32().unwrap() } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] #[inline] pub fn round_fractional_part_f64(value: f64, mut precision: usize) -> f64 { if precision > 16 { precision = 16; } else if precision == 0 { return value.round(); } let scale = 10f64.powi(precision as i32); (value * scale).round() / scale } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(not(feature = "std"))] pub fn round_fractional_part_f64(value: f64, mut precision: usize) -> f64 { debug_assert!(value >= 0.0); let value = Decimal::from_f64(value).unwrap(); if precision > 16 { precision = 16; } else if precision == 0 { return value.round().to_f64().unwrap(); } let trunc = value.trunc(); let mut fract = value.fract(); let scale = Decimal::from(10u128.pow(precision as u32)); fract = (fract * scale).round() / scale; (trunc + fract).to_f64().unwrap() } #[cfg(any(feature = "byte", feature = "bit"))] #[inline] pub(crate) fn is_zero_remainder_decimal( a: Decimal, b: Decimal, precision: usize, ) -> Option { debug_assert!(a.is_sign_positive() && b.is_sign_positive()); debug_assert!(b > Decimal::ZERO); debug_assert!(precision <= 28); let quotient = a / b; let quotient_round = { if precision == 0 { quotient.round() } else { let trunc = quotient.trunc(); let mut fract = quotient.fract(); let scale = Decimal::from(10u128.pow(precision as u32)); fract = (fract * scale).round() / scale; trunc + fract } }; if b * quotient_round == a { Some(quotient_round) } else { None } } byte-unit-5.1.4/src/errors.rs000064400000000000000000000111751046102023000142310ustar 00000000000000use core::fmt::{self, Display, Formatter}; #[cfg(any(feature = "byte", feature = "bit"))] pub use core::num::TryFromIntError; #[cfg(feature = "std")] use std::error::Error; #[cfg(any(feature = "byte", feature = "bit"))] use rust_decimal::Decimal; #[cfg(any(feature = "byte", feature = "bit"))] /// The error type returned when it exceeds representation range. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ExceededBoundsError; #[cfg(any(feature = "byte", feature = "bit"))] impl Display for ExceededBoundsError { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("value exceeds the valid range") } } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] impl Error for ExceededBoundsError {} #[cfg(any(feature = "byte", feature = "bit"))] /// The error type returned when parsing values. #[derive(Debug, Clone)] pub enum ValueParseError { ExceededBounds(Decimal), NotNumber(char), NoValue, NumberTooLong, } #[cfg(any(feature = "byte", feature = "bit"))] impl Display for ValueParseError { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::ExceededBounds(value) => { f.write_fmt(format_args!("the value {value:?} exceeds the valid range")) }, Self::NotNumber(c) => f.write_fmt(format_args!("the character {c:?} is not a number")), Self::NoValue => f.write_str("no value can be found"), Self::NumberTooLong => f.write_str("value number is too long"), } } } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] impl Error for ValueParseError {} /// The error type returned when parsing units. #[derive(Debug, Clone)] pub struct UnitParseError { pub character: char, pub expected_characters: &'static [char], pub also_expect_no_character: bool, } impl Display for UnitParseError { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let Self { character, expected_characters, also_expect_no_character, } = self; let expected_characters_length = expected_characters.len(); f.write_fmt(format_args!("the character {character:?} is incorrect",))?; if expected_characters_length == 0 { f.write_str(" (no character is expected)") } else { f.write_fmt(format_args!( " ({expected_character:?}", expected_character = expected_characters[0] ))?; if expected_characters_length > 1 { for expected_character in expected_characters[1..].iter().take(expected_characters_length - 2) { f.write_fmt(format_args!(", {expected_character:?}"))?; } if *also_expect_no_character { f.write_fmt(format_args!( ", {expected_character:?} or no character", expected_character = expected_characters[expected_characters_length - 1] ))?; } else { f.write_fmt(format_args!( " or {expected_character:?} is expected)", expected_character = expected_characters[expected_characters_length - 1] ))?; } } if *also_expect_no_character { f.write_str(" or no character")?; } f.write_str(" is expected)") } } } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] impl Error for UnitParseError {} #[cfg(any(feature = "byte", feature = "bit"))] /// The error type returned when parsing values with a unit. #[derive(Debug, Clone)] pub enum ParseError { Value(ValueParseError), Unit(UnitParseError), } #[cfg(any(feature = "byte", feature = "bit"))] impl From for ParseError { #[inline] fn from(error: ValueParseError) -> Self { Self::Value(error) } } #[cfg(any(feature = "byte", feature = "bit"))] impl From for ParseError { #[inline] fn from(error: UnitParseError) -> Self { Self::Unit(error) } } #[cfg(any(feature = "byte", feature = "bit"))] impl Display for ParseError { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { ParseError::Value(error) => Display::fmt(error, f), ParseError::Unit(error) => Display::fmt(error, f), } } } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(feature = "std")] impl Error for ParseError {} byte-unit-5.1.4/src/lib.rs000064400000000000000000000131471046102023000134640ustar 00000000000000/*! # Byte Unit A library for interaction with units of bytes. The units are **B** for 1 byte, **KB** for 1000 bytes, **MiB** for 1048576 bytes, **GB** for 1000000000 bytes, etc, and up to **E** or **Y** (if the `u128` feature is enabled). ## Usage The data types for storing the size in bits/bytes are `u64` by default, meaning the highest supported unit is up to **E**. If the `u128` feature is enabled, the data types will use `u128`, increasing the highest supported unit up to **Y**. ### Unit The enum `Unit` can be used for representing the unit of bits/bytes. ```rust use byte_unit::Unit; assert_eq!("KB", Unit::KB.as_str()); assert_eq!("MiB", Unit::MiB.as_str()); assert_eq!(Unit::KB, Unit::parse_str("K", true, true).unwrap()); assert_eq!(Unit::Kbit, Unit::parse_str("K", true, false).unwrap()); assert_eq!(Unit::KB, Unit::parse_str("KB", true, true).unwrap()); assert_eq!(Unit::KB, Unit::parse_str("Kb", true, true).unwrap()); assert_eq!(Unit::Kbit, Unit::parse_str("Kbit", true, true).unwrap()); assert_eq!(Unit::KB, Unit::parse_str("KB", false, true).unwrap()); assert_eq!(Unit::Kbit, Unit::parse_str("Kb", false, true).unwrap()); ``` ### Byte The `Byte` struct can be used for representing a size in bytes. The `from_*` associated functions can be used to create a `Byte` instance from different data types. The `as_*` methods can retrieve the size as a primitive type. ```rust # #[cfg(feature = "byte")] # { use byte_unit::{Byte, Unit}; assert_eq!(15000, Byte::from_u64(15000).as_u64()); assert_eq!(15000, Byte::from_u64_with_unit(15, Unit::KB).unwrap().as_u64()); # } ``` You can also parse a string to create a `Byte` instance. ```rust # #[cfg(feature = "byte")] # { use byte_unit::Byte; assert_eq!(50840000, Byte::parse_str("50.84 MB", true).unwrap().as_u64()); # } ``` A `Byte` instance can be formatted to string precisely. For more detailed usage, please refer to the implementation documentation of `Display::fmt` for `Byte`. ```rust # #[cfg(feature = "byte")] # { use byte_unit::Byte; let byte = Byte::from_u64(15500); assert_eq!("15500", byte.to_string()); assert_eq!("15.5 KB", format!("{byte:#}")); assert_eq!("15500 B", format!("{byte:#.0}")); # } ``` #### Arithmetic There are `add`, `subtract`, `multiply`, and `divide` methods. ```rust # #[cfg(feature = "byte")] # { use byte_unit::Byte; let a = Byte::from_u64(15500); let b = Byte::from_u64(500); assert_eq!(16000, a.add(b).unwrap().as_u64()); assert_eq!(15000, a.subtract(b).unwrap().as_u64()); assert_eq!(31000, a.multiply(2).unwrap().as_u64()); assert_eq!(3100, a.divide(5).unwrap().as_u64()); # } ``` #### Find Out an Appropriate Unit The `get_exact_unit` and `get_recoverable_unit` methods is useful if you want to find out a unit that is appropriate for a `Byte` instance. ```rust # #[cfg(feature = "byte")] # { use byte_unit::{Byte, Unit}; let byte = Byte::from_u64(50840000); assert_eq!((50840, Unit::KB), byte.get_exact_unit(false)); assert_eq!((50.84f64.try_into().unwrap(), Unit::MB), byte.get_recoverable_unit(false, 2)); assert_eq!((50840.into(), Unit::KB), byte.get_recoverable_unit(false, 0)); # } ``` #### AdjustedByte The `AdjustedByte` struct can be used for roughly representing a size of bytes with a unit. To change the unit of a `Byte` instance, you can use the `get_adjusted_unit` method. An `AdjustedByte` instance can be formatted to string. For more detailed usage, please refer to the implementation documentation of `Display::fmt` for `AdjustedByte`. ```rust # #[cfg(feature = "byte")] # { use byte_unit::{Byte, Unit}; let byte = Byte::parse_str("123KiB", true).unwrap(); let adjusted_byte = byte.get_adjusted_unit(Unit::KB); assert_eq!("125.952 KB", adjusted_byte.to_string()); assert_eq!("125.95 KB", format!("{adjusted_byte:.2}")); # } ``` The `get_appropriate_unit` method can be used to automatically find an appropriate unit for creating an `AdjustedByte` instance. ```rust # #[cfg(feature = "byte")] # { use byte_unit::{Byte, Unit, UnitType}; let byte = Byte::from_u64(1500000); let adjusted_byte = byte.get_appropriate_unit(UnitType::Binary); assert_eq!("1.43 MiB", format!("{adjusted_byte:.2}")); # } ``` ### Bit The `Bit` struct can be used for representing a size in bits. The `bit` feature must be enabled. Usage of the `Bit` struct and the `Byte` struct is very similar. Also, There is the `AdjustedBit` struct. The difference lies in the fact that the `parse_str` method of the `Bit` struct cannot be configured to ignore case; it always does not ignore case. ```rust # #[cfg(feature = "bit")] # { use byte_unit::{Bit, Unit}; let bit = Bit::parse_str("123Kib").unwrap(); let adjusted_bit = bit.get_adjusted_unit(Unit::Kbit); assert_eq!("125.952 Kb", adjusted_bit.to_string()); assert_eq!("125.95 Kb", format!("{adjusted_bit:.2}")); # } ``` ## No Std Disable the default features to compile this crate without std. ```toml [dependencies.byte-unit] version = "*" default-features = false features = ["byte"] ``` ## Serde Support Enable the `serde` feature to support the serde framework. ```toml [dependencies.byte-unit] version = "*" features = ["serde"] ``` ## Rocket Support Enable the `rocket` feature to support the Rocket framework. ```toml [dependencies.byte-unit] version = "*" features = ["rocket"] ``` */ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #[cfg(feature = "serde")] #[macro_use] extern crate alloc; #[cfg(feature = "rust_decimal")] pub extern crate rust_decimal; #[cfg(feature = "bit")] mod bit; #[cfg(feature = "byte")] mod byte; mod common; mod errors; mod unit; #[cfg(feature = "bit")] pub use bit::*; #[cfg(feature = "byte")] pub use byte::*; pub use errors::*; pub use unit::*; byte-unit-5.1.4/src/unit/built_in_trait.rs000064400000000000000000000011701046102023000166760ustar 00000000000000use core::str::FromStr; use super::Unit; use crate::UnitParseError; impl FromStr for Unit { type Err = UnitParseError; /// `ignore_case` is set to `false`; `prefer_byte` is set to `true`. See [`Unit::parse_str`](#method.parse_str). #[inline] fn from_str(s: &str) -> Result { Unit::parse_str(s, false, true) } } impl From for u128 { /// See [`Unit::as_bits_u128`](#method.as_bits_u128). #[inline] fn from(unit: Unit) -> Self { unit.as_bits_u128() } } impl AsRef for Unit { #[inline] fn as_ref(&self) -> &str { self.as_str() } } byte-unit-5.1.4/src/unit/mod.rs000064400000000000000000000315121046102023000144500ustar 00000000000000mod built_in_trait; pub(crate) mod parse; #[cfg(feature = "rocket")] mod rocket_traits; #[cfg(feature = "serde")] mod serde_traits; #[cfg(any(feature = "byte", feature = "bit"))] mod unit_type; use core::fmt::{self, Display, Formatter}; #[cfg(any(feature = "byte", feature = "bit"))] pub use unit_type::*; /// The unit of bits/bytes. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Unit { /// 8 Bit = 1 byte. Bit, /// 1 B = 1 byte. B, /// 1 Kbit = 125 bytes. Kbit, /// 1 Kibit = 27 bytes. Kibit, /// 1 KB = 103 bytes. KB, /// 1 KiB = 210 bytes. KiB, /// 1 Mbit = 125 * 103 bytes. Mbit, /// 1 Mibit = 217 bytes. Mibit, /// 1 MB = 106 bytes. MB, /// 1 MiB = 220 bytes. MiB, /// 1 Gbit = 125 * 106 bytes. Gbit, /// 1 Gibit = 227 bytes. Gibit, /// 1 GB = 109 bytes. GB, /// 1 GiB = 230 bytes. GiB, /// 1 Tbit = 125 * 109 bytes. Tbit, /// 1 Tibit = 237 bytes. Tibit, /// 1 TB = 1012 bytes. TB, /// 1 TiB = 240 bytes. TiB, /// 1 Pbit = 125 * 1012 bytes. Pbit, /// 1 Pibit = 247 bytes. Pibit, /// 1 PB = 1015 bytes. PB, /// 1 PiB = 250 bytes. PiB, /// 1 Ebit = 125 * 1015 bytes. Ebit, /// 1 Eibit = 257 bytes. Eibit, /// 1 EB = 1018 bytes. EB, /// 1 EiB = 260 bytes. EiB, #[cfg(feature = "u128")] /// 1 Zbit = 125 * 1018 bytes. Zbit, #[cfg(feature = "u128")] /// 1 Zibit = 267 bytes. Zibit, #[cfg(feature = "u128")] /// 1 ZB = 1021 bytes. ZB, #[cfg(feature = "u128")] /// 1 ZiB = 270 bytes. ZiB, #[cfg(feature = "u128")] /// 1 Ybit = 125 * 1021 bytes. Ybit, #[cfg(feature = "u128")] /// 1 Yibit = 277 bytes. Yibit, #[cfg(feature = "u128")] /// 1 YB = 1024 bytes. YB, #[cfg(feature = "u128")] /// 1 YiB = 280 bytes. YiB, } impl Display for Unit { #[inline] fn fmt(&self, f: &mut Formatter) -> fmt::Result { Display::fmt(self.as_str(), f) } } /// Methods for converting a `Unit` instance into a primitive integer. impl Unit { /// Retrieve the bit represented by this `Unit` instance. /// /// # Examples /// /// ``` /// use byte_unit::Unit; /// /// assert_eq!(1, Unit::Bit.as_bits_u128()); /// assert_eq!(8, Unit::B.as_bits_u128()); /// assert_eq!(8000, Unit::KB.as_bits_u128()); /// assert_eq!(1024, Unit::Kibit.as_bits_u128()); /// ``` #[inline] pub const fn as_bits_u128(self) -> u128 { match self { Unit::Bit => 1, Unit::B => 1 << 3, Unit::Kbit => 1_000, Unit::Kibit => 1 << 10, Unit::KB => Unit::Kbit.as_bits_u128() << 3, Unit::KiB => Unit::Kibit.as_bits_u128() << 3, Unit::Mbit => 1_000_000, Unit::Mibit => 1 << 20, Unit::MB => Unit::Mbit.as_bits_u128() << 3, Unit::MiB => Unit::Mibit.as_bits_u128() << 3, Unit::Gbit => 1_000_000_000, Unit::Gibit => 1 << 30, Unit::GB => Unit::Gbit.as_bits_u128() << 3, Unit::GiB => Unit::Gibit.as_bits_u128() << 3, Unit::Tbit => 1_000_000_000_000, Unit::Tibit => 1 << 40, Unit::TB => Unit::Tbit.as_bits_u128() << 3, Unit::TiB => Unit::Tibit.as_bits_u128() << 3, Unit::Pbit => 1_000_000_000_000_000, Unit::Pibit => 1 << 50, Unit::PB => Unit::Pbit.as_bits_u128() << 3, Unit::PiB => Unit::Pibit.as_bits_u128() << 3, Unit::Ebit => 1_000_000_000_000_000_000, Unit::Eibit => 1 << 60, Unit::EB => Unit::Ebit.as_bits_u128() << 3, Unit::EiB => Unit::Eibit.as_bits_u128() << 3, #[cfg(feature = "u128")] Unit::Zbit => 1_000_000_000_000_000_000_000, #[cfg(feature = "u128")] Unit::Zibit => 1 << 70, #[cfg(feature = "u128")] Unit::ZB => Unit::Zbit.as_bits_u128() << 3, #[cfg(feature = "u128")] Unit::ZiB => Unit::Zibit.as_bits_u128() << 3, #[cfg(feature = "u128")] Unit::Ybit => 1_000_000_000_000_000_000_000_000, #[cfg(feature = "u128")] Unit::Yibit => 1 << 80, #[cfg(feature = "u128")] Unit::YB => Unit::Ybit.as_bits_u128() << 3, #[cfg(feature = "u128")] Unit::YiB => Unit::Yibit.as_bits_u128() << 3, } } #[cfg(any(feature = "byte", feature = "bit"))] #[cfg(not(feature = "u128"))] #[inline] pub(crate) const fn as_bits_u64(self) -> u64 { self.as_bits_u128() as u64 } #[cfg(feature = "byte")] #[inline] pub(crate) const fn as_bytes_u128(self) -> u128 { debug_assert!(!matches!(self, Unit::Bit)); self.as_bits_u128() >> 3 } #[cfg(feature = "byte")] #[cfg(not(feature = "u128"))] #[inline] pub(crate) const fn as_bytes_u64(self) -> u64 { debug_assert!(!matches!(self, Unit::Bit)); self.as_bits_u64() >> 3 } } /// Methods for converting a `Unit` instance into a string. impl Unit { /// Retrieve the string represented by this `Unit` instance. /// /// # Examples /// /// ``` /// use byte_unit::Unit; /// /// assert_eq!("B", Unit::B.as_str()); /// assert_eq!("KB", Unit::KB.as_str()); /// assert_eq!("MiB", Unit::MiB.as_str()); /// assert_eq!("Gb", Unit::Gbit.as_str()); /// assert_eq!("Tib", Unit::Tibit.as_str()); /// ``` #[inline] pub const fn as_str(self) -> &'static str { match self { Self::Bit => "b", Self::B => "B", Self::Kbit => "Kb", Self::Kibit => "Kib", Self::KB => "KB", Self::KiB => "KiB", Self::Mbit => "Mb", Self::Mibit => "Mib", Self::MB => "MB", Self::MiB => "MiB", Self::Gbit => "Gb", Self::Gibit => "Gib", Self::GB => "GB", Self::GiB => "GiB", Self::Tbit => "Tb", Self::Tibit => "Tib", Self::TB => "TB", Self::TiB => "TiB", Self::Pbit => "Pb", Self::Pibit => "Pib", Self::PB => "PB", Self::PiB => "PiB", Self::Ebit => "Eb", Self::Eibit => "Eib", Self::EB => "EB", Self::EiB => "EiB", #[cfg(feature = "u128")] Self::Zbit => "Zb", #[cfg(feature = "u128")] Self::Zibit => "Zib", #[cfg(feature = "u128")] Self::ZB => "ZB", #[cfg(feature = "u128")] Self::ZiB => "ZiB", #[cfg(feature = "u128")] Self::Ybit => "Yb", #[cfg(feature = "u128")] Self::Yibit => "Yib", #[cfg(feature = "u128")] Self::YB => "YB", #[cfg(feature = "u128")] Self::YiB => "YiB", } } } /// Methods for categorizing variants. impl Unit { /// Check whether the unit is based on bits. /// /// # Examples /// /// ``` /// use byte_unit::Unit; /// /// assert_eq!(false, Unit::KB.is_bit()); /// assert_eq!(true, Unit::Kbit.is_bit()); /// ``` #[inline] pub const fn is_bit(self) -> bool { #[cfg(feature = "u128")] { matches!( self, Self::Bit | Self::Kbit | Self::Kibit | Self::Mbit | Self::Mibit | Self::Gbit | Self::Gibit | Self::Tbit | Self::Tibit | Self::Pbit | Self::Pibit | Self::Ebit | Self::Eibit | Self::Zbit | Self::Zibit | Self::Ybit | Self::Yibit ) } #[cfg(not(feature = "u128"))] { matches!( self, Self::Bit | Self::Kbit | Self::Kibit | Self::Mbit | Self::Mibit | Self::Gbit | Self::Gibit | Self::Tbit | Self::Tibit | Self::Pbit | Self::Pibit | Self::Ebit | Self::Eibit ) } } /// Check whether the unit is based on powers of **2**. /// /// # Examples /// /// ``` /// use byte_unit::Unit; /// /// assert_eq!(false, Unit::KB.is_binary_multiples()); /// assert_eq!(true, Unit::KiB.is_binary_multiples()); /// ``` #[inline] pub const fn is_binary_multiples(self) -> bool { #[cfg(feature = "u128")] { matches!( self, Self::B | Self::Kibit | Self::KiB | Self::Mibit | Self::MiB | Self::Gibit | Self::GiB | Self::Tibit | Self::TiB | Self::Pibit | Self::PiB | Self::Eibit | Self::EiB | Self::Zibit | Self::ZiB | Self::Yibit | Self::YiB ) } #[cfg(not(feature = "u128"))] { matches!( self, Self::B | Self::Kibit | Self::KiB | Self::Mibit | Self::MiB | Self::Gibit | Self::GiB | Self::Tibit | Self::TiB | Self::Pibit | Self::PiB | Self::Eibit | Self::EiB ) } } } impl Unit { #[cfg(any(feature = "byte", feature = "bit"))] #[allow(dead_code)] #[inline] pub(crate) const fn get_multiples() -> &'static [Self] { &[ Self::Kbit, Self::Kibit, Self::KB, Self::KiB, Self::Mbit, Self::Mibit, Self::MB, Self::MiB, Self::Gbit, Self::Gibit, Self::GB, Self::GiB, Self::Tbit, Self::Tibit, Self::TB, Self::TiB, Self::Pbit, Self::Pibit, Self::PB, Self::PiB, Self::Ebit, Self::Eibit, Self::EB, Self::EiB, #[cfg(feature = "u128")] Self::Zbit, #[cfg(feature = "u128")] Self::Zibit, #[cfg(feature = "u128")] Self::ZB, #[cfg(feature = "u128")] Self::ZiB, #[cfg(feature = "u128")] Self::Ybit, #[cfg(feature = "u128")] Self::Yibit, #[cfg(feature = "u128")] Self::YB, #[cfg(feature = "u128")] Self::YiB, ] } #[cfg(feature = "byte")] #[inline] pub(crate) const fn get_multiples_bytes() -> &'static [Self] { &[ Self::KB, Self::KiB, Self::MB, Self::MiB, Self::GB, Self::GiB, Self::TB, Self::TiB, Self::PB, Self::PiB, Self::EB, Self::EiB, #[cfg(feature = "u128")] Self::ZB, #[cfg(feature = "u128")] Self::ZiB, #[cfg(feature = "u128")] Self::YB, #[cfg(feature = "u128")] Self::YiB, ] } #[cfg(feature = "bit")] #[allow(dead_code)] #[inline] pub(crate) const fn get_multiples_bits() -> &'static [Self] { &[ Self::Kbit, Self::Kibit, Self::Mbit, Self::Mibit, Self::Gbit, Self::Gibit, Self::Tbit, Self::Tibit, Self::Pbit, Self::Pibit, Self::Ebit, Self::Eibit, #[cfg(feature = "u128")] Self::Zbit, #[cfg(feature = "u128")] Self::Zibit, #[cfg(feature = "u128")] Self::Ybit, #[cfg(feature = "u128")] Self::Yibit, ] } } byte-unit-5.1.4/src/unit/parse.rs000064400000000000000000000226661046102023000150150ustar 00000000000000use core::str::Bytes; use super::Unit; use crate::{common::get_char_from_bytes, UnitParseError}; /// Associated functions for parsing strings. impl Unit { /// Create a new `Unit` instance from a string. /// The string may be `""`, `"B"`, `"M"`, `"MB"`, `"MiB"`, `"b"`, `"Mb"`, `"Mbit"`. /// /// You can ignore the case of **"B"** (byte), which means **b** will still be treated as bytes instead of bits. /// /// If the input string is empty, it will return `B` if `prefer_byte` is true; otherwise, it will return `b`. Similarly, if the string is not empty but it does not explicitly contains `"B"`, `"b"`, or `"bit"`, it will imply the base is `"B"` if `prefer_byte` is true; otherwise, imply the base is `"b"`. /// /// # Examples /// /// ``` /// # use byte_unit::Unit; /// let unit = Unit::parse_str("Kib", true, true).unwrap(); // KiB /// ``` /// /// ``` /// # use byte_unit::Unit; /// let unit = Unit::parse_str("Kib", false, true).unwrap(); // Kibit /// ``` pub fn parse_str>( s: S, ignore_case: bool, prefer_byte: bool, ) -> Result { let s = s.as_ref().trim(); let mut bytes = s.bytes(); read_xib(bytes.next(), bytes, ignore_case, prefer_byte) } } pub(crate) fn read_xib( e: Option, bytes: Bytes, ignore_case: bool, prefer_byte: bool, ) -> Result { match e { Some(e) => match e.to_ascii_uppercase() { b'B' => { let byte = read_b(bytes, if ignore_case { true } else { e == b'B' })?; if byte { Ok(Unit::B) } else { Ok(Unit::Bit) } }, b'K' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::KiB) } else { Ok(Unit::Kibit) } } else if byte { Ok(Unit::KB) } else { Ok(Unit::Kbit) } }, b'M' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::MiB) } else { Ok(Unit::Mibit) } } else if byte { Ok(Unit::MB) } else { Ok(Unit::Mbit) } }, b'G' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::GiB) } else { Ok(Unit::Gibit) } } else if byte { Ok(Unit::GB) } else { Ok(Unit::Gbit) } }, b'T' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::TiB) } else { Ok(Unit::Tibit) } } else if byte { Ok(Unit::TB) } else { Ok(Unit::Tbit) } }, b'P' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::PiB) } else { Ok(Unit::Pibit) } } else if byte { Ok(Unit::PB) } else { Ok(Unit::Pbit) } }, b'E' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::EiB) } else { Ok(Unit::Eibit) } } else if byte { Ok(Unit::EB) } else { Ok(Unit::Ebit) } }, #[cfg(feature = "u128")] b'Z' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::ZiB) } else { Ok(Unit::Zibit) } } else if byte { Ok(Unit::ZB) } else { Ok(Unit::Zbit) } }, #[cfg(feature = "u128")] b'Y' => { let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?; if i { if byte { Ok(Unit::YiB) } else { Ok(Unit::Yibit) } } else if byte { Ok(Unit::YB) } else { Ok(Unit::Ybit) } }, _ => { #[cfg(feature = "u128")] { Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters: &['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'], also_expect_no_character: true, }) } #[cfg(not(feature = "u128"))] { Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters: &['B', 'K', 'M', 'G', 'T', 'P', 'E'], also_expect_no_character: true, }) } }, }, None => Ok(if prefer_byte { Unit::B } else { Unit::Bit }), } } fn read_ib( mut bytes: Bytes, ignore_case: bool, default_upper_case: bool, ) -> Result<(bool, bool), UnitParseError> { match bytes.next() { Some(mut e) => { let i = e == b'i' || e == b'I'; if i { match bytes.next() { Some(ne) => e = ne, None => return Ok((true, default_upper_case)), } } match e { b'b' | b'B' => Ok((i, read_b(bytes, if ignore_case { true } else { e == b'B' })?)), _ => { let expected_characters: &[char] = if ignore_case { if default_upper_case { &['B'] } else { &['b'] } } else { &['B', 'b'] }; Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters, also_expect_no_character: true, }) }, } }, None => Ok((false, default_upper_case)), } } fn read_b(mut bytes: Bytes, byte: bool) -> Result { match bytes.next() { Some(e) => match e.to_ascii_lowercase() { b'i' => match bytes.next() { Some(e) => match e.to_ascii_lowercase() { b't' => match bytes.next() { Some(e) => match e.to_ascii_lowercase() { b's' => match bytes.next() { Some(e) => Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters: &[], also_expect_no_character: true, }), None => Ok(false), }, _ => Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters: &['s'], also_expect_no_character: true, }), }, None => Ok(false), }, _ => Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters: &['t'], also_expect_no_character: false, }), }, None => Err(UnitParseError { character: 'i', expected_characters: &[], also_expect_no_character: true, }), }, _ => Err(UnitParseError { character: unsafe { get_char_from_bytes(e, bytes) }, expected_characters: &['i'], also_expect_no_character: true, }), }, None => Ok(byte), } } byte-unit-5.1.4/src/unit/rocket_traits.rs000064400000000000000000000010151046102023000165410ustar 00000000000000use std::str::FromStr; use rocket::{ form::{self, FromFormField, ValueField}, request::FromParam, }; use super::Unit; use crate::UnitParseError; impl<'r> FromParam<'r> for Unit { type Error = UnitParseError; #[inline] fn from_param(v: &'r str) -> Result { Self::from_str(v) } } impl<'r> FromFormField<'r> for Unit { #[inline] fn from_value(v: ValueField<'r>) -> form::Result<'r, Self> { Ok(Self::from_str(v.value).map_err(form::Error::custom)?) } } byte-unit-5.1.4/src/unit/serde_traits.rs000064400000000000000000000021271046102023000163610ustar 00000000000000use core::{fmt, fmt::Formatter, str::FromStr}; use serde::{ self, de::{Error as DeError, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use super::Unit; impl Serialize for Unit { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(self.as_str()) } } impl<'de> Deserialize<'de> for Unit { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct MyVisitor; impl<'de> Visitor<'de> for MyVisitor { type Value = Unit; #[inline] fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a string such as \"B\", \"KB\" or \"MiB\"") } #[inline] fn visit_str(self, v: &str) -> Result where E: DeError, { Unit::from_str(v).map_err(DeError::custom) } } deserializer.deserialize_str(MyVisitor) } } byte-unit-5.1.4/src/unit/unit_type.rs000064400000000000000000000004401046102023000157050ustar 00000000000000/// Choose how to find an appropriate unit based on a base of 2 or 10. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UnitType { /// KiB, MiB, ..., etc. Binary, /// KB, MB, ..., etc. Decimal, /// Use both binary and decimal, choose the closest one. Both, }