1 unstable release
new 0.1.0 | Jan 9, 2025 |
---|
#11 in #byte-size
32KB
627 lines
Helper crate to work with bit, byte, and block sizes.
This crate provides three dedicated types, NumBits
, NumBytes
, and
NumBlocks
, to represent numbers of bits, bytes, and blocks, respectively. It
implements the usual traits for numeric operators such that calculations on them can
be carried out with succinct syntax. All operations will panic on errors, such as
over- or underflows. This is an intentional design decision to prevent subtly
incorrect results and behavior. In addition, this crate provides formatting and
parsing for byte sizes.
This crate is no_std
-compatible.
Conversions
The provided types support convenient conversions to each other:
assert_eq!(NumBits::new(15).to_bytes_ceil(), NumBytes::bytes(2));
assert_eq!(NumBits::new(15).to_bytes_floor(), NumBytes::bytes(1));
assert_eq!(NumBytes::bytes(2).to_bits(), NumBits::new(16));
assert_eq!(NumBits::from(NumBytes::bytes(2)), NumBits::new(16));
const BLOCK_SIZE: NumBytes = NumBytes::kibibytes(4);
assert_eq!(NumBytes::bytes(8193).to_blocks_ceil(BLOCK_SIZE), NumBlocks::new(3));
assert_eq!(NumBytes::bytes(8193).to_blocks_floor(BLOCK_SIZE), NumBlocks::new(2));
assert_eq!(NumBlocks::new(2).to_bytes(BLOCK_SIZE), NumBytes::kibibytes(8));
Calculations
Calculations can be performed with the types as well as with [u64
] integers:
assert_eq!(NumBytes::bytes(10) / NumBytes::bytes(2), NumBytes::bytes(5));
assert_eq!(NumBytes::bytes(10) / 2, NumBytes::bytes(5));
assert_eq!(NumBits::new(5) + NumBits::new(8), NumBits::new(13));
assert_eq!(NumBits::new(5) * 2, NumBits::new(10));
assert_eq!(NumBlocks::new(10) + 2, NumBlocks::new(12));
assert_eq!(NumBits::new(2) + NumBytes::bytes(1), NumBits::new(10));
Comparisons
Comparisons are supported on the types as well as with [u64
] integers:
assert!(NumBytes::bytes(10) < 20);
assert!(NumBytes::bytes(10) != 0);
assert_eq!(NumBits::new(5), 5);
assert_eq!(NumBits::new(16), NumBytes::new(2));
assert!(NumBits::new(15) < NumBytes::new(2));
Formatting
Formatting of byte sizes maximizes the unit while minimizing the integer part towards one. For example:
assert_eq!(NumBytes::mebibytes(128).to_string(), "128MiB");
assert_eq!(NumBytes::gigabytes(1).to_string(), "1GB");
assert_eq!(NumBytes::bytes(1023).to_string(), "1.023kB");
assert_eq!(NumBytes::bytes(1000).to_string(), "1kB");
assert_eq!(NumBytes::bytes(999).to_string(), "999B");
assert_eq!(NumBytes::bytes(2560).to_string(), "2.5KiB");
The usual formatting syntax can be used to limit the precision:
assert_eq!(format!("{:.2}", NumBytes::terabytes(2)), "1.81TiB");
Parsing
Byte sizes must follow the following syntax:
⟨byte-size⟩ ::= ⟨int⟩ [ '.' ⟨int⟩ ] [ ' '* ⟨unit⟩ ]
⟨int⟩ ::= [0-9_]+
⟨unit⟩ ::= 'B' | 'K' … 'E' | 'kB' … 'EB' | 'KiB' … 'EiB' (case-insensitive)
The units (K
... E
) are interpreted as binary units (KiB
... EiB
). Generally,
unit parsing is case-insensitive.
assert_eq!(NumBytes::from_str("5").unwrap(), NumBytes::bytes(5));
assert_eq!(NumBytes::from_str("2.5KiB").unwrap(), NumBytes::bytes(2560));
assert_eq!(NumBytes::from_str("2_000kB").unwrap(), NumBytes::megabytes(2));
Parsing also works in const
contexts using NumBytes::parse_str
or
NumBytes::parse_ascii
:
const BLOCK_SIZE: NumBytes = match NumBytes::parse_str("4KiB") {
Ok(value) => value,
Err(_) => panic!("invalid format"),
};
The parser has been extensively fuzz-tested, ensuring that no input leads to panics.
Serialization and Deserialization
By enabling the serde
feature, NumBits
, NumBytes
, and NumBlocks
can be
serialized and deserialized. All tree types always serialize as [u64
] integers.
Deserialization of NumBytes
is also supported from strings.
Dependencies
~160KB