mirror of
https://github.com/LeopoldArkham/humansize
synced 2024-11-10 06:14:15 +00:00
Version 2.0.0
This commit is contained in:
parent
44802b23bb
commit
328bde1bdc
19 changed files with 589 additions and 279 deletions
|
@ -1,19 +1,20 @@
|
|||
[package]
|
||||
name = "humansize"
|
||||
version = "1.1.1"
|
||||
version = "2.0.0"
|
||||
authors = ["Leopold Arkham <leopold.arkham@gmail.com>"]
|
||||
edition = "2021"
|
||||
readme = "README.md"
|
||||
description = "A configurable crate to easily represent file sizes in a human-readable format."
|
||||
description = "A configurable crate to easily represent sizes in a human-readable format."
|
||||
repository = "https://github.com/LeopoldArkham/humansize"
|
||||
homepage = "https://github.com/LeopoldArkham/humansize"
|
||||
documentation = "https://docs.rs/humansize"
|
||||
keywords = ["file", "size", "sizes", "humanize", "bytes", "file size", "size formatting"]
|
||||
keywords = ["size", "formatting", "humanize", "file-size"]
|
||||
categories = ["value-formatting"]
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[features]
|
||||
no_alloc = []
|
||||
impl_style = []
|
||||
|
||||
[dependencies]
|
||||
libm = "0.2.5"
|
||||
|
|
125
README.md
125
README.md
|
@ -1,48 +1,116 @@
|
|||
# **Humansize** ![travis badge](https://travis-ci.org/LeopoldArkham/humansize.svg?branch=master)
|
||||
|
||||
[Documentation](https://docs.rs/humansize/0.1.0/humansize/)
|
||||
[Documentation](https://docs.rs/humansize/latest/humansize/)
|
||||
|
||||
|
||||
## Features
|
||||
Humansize is a humanization library for information size that is:
|
||||
- Simple & convenient to use
|
||||
- Customizable
|
||||
- Supports byte or bit sizes
|
||||
- `no-std`
|
||||
- Optionally non-allocating
|
||||
- Optionally accepts signed values
|
||||
|
||||
## How to use it...
|
||||
|
||||
Humansize lets you easily represent file sizes in a human-friendly format.
|
||||
You can specify your own formatting style or pick among the three defaults provided
|
||||
by the library:
|
||||
|
||||
* Decimal (kilo = 1000, unit format is `kB`)
|
||||
* Binary (kilo = 1024, unit format is `KiB`)
|
||||
* Windows/Conventional (kilo = 1024, unit format is `kB`)
|
||||
|
||||
## How to use it
|
||||
|
||||
Cargo.Toml:
|
||||
```
|
||||
Add humansize as a dependency to your project's `cargo.toml`:
|
||||
```toml
|
||||
[dependencies]
|
||||
humansize = "1.1.1"
|
||||
...
|
||||
humansize = "2.0.0"
|
||||
```
|
||||
|
||||
Simply import the `FileSize` trait and the options module and call the
|
||||
file_size method on any positive integer, using one of the three standards
|
||||
provided by the options module.
|
||||
### ... to easily format a size:
|
||||
|
||||
```rust,no_run
|
||||
extern crate humansize;
|
||||
use humansize::{FileSize, file_size_opts as options};
|
||||
1. Import the `format_size` function as well as your preferred set of defaults:
|
||||
- `DECIMAL` (SI)
|
||||
- `BINARY` (IEC)
|
||||
- `WINDOWS` (IEC values but SI units)
|
||||
2. Call `format_size` with an unsigned integer
|
||||
|
||||
fn main() {
|
||||
let size = 1000;
|
||||
println!("Size is {}", size.file_size(options::DECIMAL).unwrap());
|
||||
```rust
|
||||
use humansize::{format_size, DECIMAL};
|
||||
|
||||
println!("Size is {}", size.file_size(options::BINARY).unwrap());
|
||||
let size = 1_000_000u64;
|
||||
let res: String = format_size(size, DECIMAL);
|
||||
|
||||
assert_eq!(&res, "1 MB");
|
||||
|
||||
println!("Size is {}", size.file_size(options::CONVENTIONAL).unwrap());
|
||||
}
|
||||
```
|
||||
|
||||
If you wish to customize the way sizes are displayed, you may create your own custom `FormatSizeOptions` struct
|
||||
and pass that to the method. See the `custom_options.rs` file in the example folder.
|
||||
### ... to format many sizes:
|
||||
To improve reusability, you can use `create_format`, which returns a formatter function akin to `format_size` but with the options argument curried so it doesn't need to be specified again:
|
||||
|
||||
```rust
|
||||
use humansize::{make_format, DECIMAL};
|
||||
|
||||
let formatter = make_format(DECIMAL);
|
||||
|
||||
assert_eq!(formatter(1_000_000u64), "1 MB");
|
||||
assert_eq!(formatter(1_000_000_000u64), "1 GB");
|
||||
//...
|
||||
|
||||
```
|
||||
|
||||
### ... to avoid allocation:
|
||||
Specify the `no_alloc` feature flag in your project's `cargo.toml`:
|
||||
```toml
|
||||
[dependencies]
|
||||
...
|
||||
humansize = { version = "2.0.0", features = ["no_alloc"] }
|
||||
```
|
||||
This excludes all allocating code from compilation. You may now use the library's internal `Formatter` struct, which implements `core::fmt::display` so that you can `write!` it to a custom buffer of your choice:
|
||||
```rust
|
||||
use humansize::{Formatter, DECIMAL};
|
||||
|
||||
let formatter = Formatter::new(1_000_000, DECIMAL);
|
||||
assert_eq!(format!({}, formatter), '1 MB');
|
||||
```
|
||||
### ... with the `impl` style API:
|
||||
For stylistic reasons, you may prefer to use the impl-style API of earlier versions of the crate.
|
||||
To do so, specify the `impl-style` feature flag in your project's `cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
...
|
||||
humansize = { version = "2.0.0", features = ["impl_style"] }
|
||||
```
|
||||
Enabling this feature makes two methods available:
|
||||
- `format_size` on unsigned integers types
|
||||
- `format_size_i` on signed integer types.
|
||||
|
||||
To use it, bring the FormatSize trait into scope and call its method on an integer type:
|
||||
```rust
|
||||
use humansize::{FormatSize, Decimal};
|
||||
|
||||
assert_eq!(1_000_000u64.format_size(DECIMAL), "1 MB");
|
||||
assert_eq!(-1_000_000).format_size_i(DECIMAL), "-1 MB");
|
||||
```
|
||||
### ... to further customize the output:
|
||||
Humansize exports three default option sets:
|
||||
* `Decimal`: kilo = 1000, unit format is `XB`.
|
||||
* `Binary`: kilo = 1024, unit format is `XiB`.
|
||||
* `WINDOWS` (Windows): kilo = 1024, unit format is `XB`.
|
||||
|
||||
The formatting can be further customized by providing providing your own option set. See the documentation of the `FormatSizeOptions` struct to see all the addressable parameters, and [this example](examples/custom_options.rs) for its usage.
|
||||
|
||||
### ... to accept negative values:
|
||||
The solutions presented above only accept unsigned integer types as input (`usize`, `8`, `u16`, `u32` and `u64`). If however accepting negative values is correct for your application, a signed alternative exists for each of them that will accept signed integer types, and format them accordingly if negative:
|
||||
|
||||
- `format_size` : `format_size_i`
|
||||
- `create_format` : `create_format_i`
|
||||
- `FormatSize` trait : `FormatSizeI` trait
|
||||
- `SizeFormatter` : `ISizeFormatter`
|
||||
```rust
|
||||
use humansize::{format_size_i, make_format_i, DECIMAL};
|
||||
|
||||
assert_eq!(&format_size_i(-1_000_000, DECIMAL), "-1 MB");
|
||||
|
||||
let signed_formatter = make_format_i(DECIMAL);
|
||||
assert_eq!(&signed_formatter(-1_000_000), "-1 MB");
|
||||
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
@ -53,7 +121,6 @@ This project is licensed under either of
|
|||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
|
|
|
@ -1,27 +1,11 @@
|
|||
extern crate humansize;
|
||||
use humansize::{format_size, format_size_i, FixedAt, FormatSizeOptions, Kilo, DECIMAL};
|
||||
use humansize::{format_size, FormatSizeOptions, DECIMAL};
|
||||
|
||||
fn main() {
|
||||
// Declare a fully custom option struct
|
||||
let custom_options = FormatSizeOptions {
|
||||
kilo: Kilo::Binary,
|
||||
units: Kilo::Decimal,
|
||||
decimal_places: 3,
|
||||
decimal_zeroes: 1,
|
||||
fixed_at: FixedAt::No,
|
||||
long_units: true,
|
||||
space: false,
|
||||
suffix: "",
|
||||
};
|
||||
// Create a new FormatSizeOptions struct starting from one of the defaults
|
||||
let custom_options = FormatSizeOptions::from(DECIMAL).decimal_places(5);
|
||||
|
||||
// Then use it
|
||||
println!("{}", format_size(3024usize, custom_options));
|
||||
|
||||
// Or use only some custom parameters and adopt the rest from an existing config
|
||||
let semi_custom_options = FormatSizeOptions {
|
||||
decimal_zeroes: 3,
|
||||
..DECIMAL
|
||||
};
|
||||
|
||||
println!("{}", format_size_i(1000, semi_custom_options));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
extern crate humansize;
|
||||
//Import the trait and the options module
|
||||
use humansize::{format_size, BINARY, CONVENTIONAL, DECIMAL};
|
||||
|
||||
use humansize::{format_size, format_size_i, BINARY, WINDOWS, DECIMAL, Formatter, IFormatter};
|
||||
|
||||
|
||||
fn main() {
|
||||
// Call the file_size method on any non-negative integer with the option set you require
|
||||
|
||||
println!("{}", format_size(5456usize, BINARY));
|
||||
println!("{}", format_size(1024usize, BINARY));
|
||||
println!("{}", format_size(1000usize, DECIMAL));
|
||||
println!("{}", format_size(1_023_654_123_654_u64, DECIMAL));
|
||||
println!("{}", format_size(123456789usize, CONVENTIONAL));
|
||||
println!("{}", format_size(1024usize, DECIMAL));
|
||||
println!("{}", format_size(1000usize, WINDOWS));
|
||||
|
||||
println!("{}", format_size(1_023_654_123_654_u64, BINARY));
|
||||
println!("{}", format_size(123456789usize, DECIMAL));
|
||||
println!("{}", format_size_i(-123456789, WINDOWS));
|
||||
|
||||
println!("{}", Formatter::new(1234u32, BINARY));
|
||||
println!("{}", IFormatter::new(1234, BINARY));
|
||||
|
||||
}
|
||||
|
|
7
feature-tests/impl-style/cargo.toml
Normal file
7
feature-tests/impl-style/cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "impl-style"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
humansize = { path = "../..", features = ["impl_style"] }
|
0
feature-tests/impl-style/src/lib.rs
Normal file
0
feature-tests/impl-style/src/lib.rs
Normal file
9
feature-tests/impl-style/tests/impl_style.rs
Normal file
9
feature-tests/impl-style/tests/impl_style.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// This sub-crate exists to make sure that everything works well with the `impl-style` flag enabled
|
||||
|
||||
use humansize::{FormatSize, FormatSizeI, DECIMAL};
|
||||
|
||||
#[test]
|
||||
fn test_impl_style() {
|
||||
assert_eq!(1000u64.format_size(DECIMAL), "1 kB");
|
||||
assert_eq!((-1000).format_size_i(DECIMAL), "-1 kB");
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// This sub-crate exists to make sure that everything works well with the `no_alloc` flag enabled
|
||||
use std::io::Write;
|
||||
|
||||
use humansize::{Formatter, DECIMAL};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut result: [u8; 4] = [0, 0, 0, 0];
|
||||
write!(&mut result[..], "{}", Formatter::new(1000usize, DECIMAL)).unwrap();
|
||||
assert_eq!(core::str::from_utf8(&result).unwrap(), "1 kB");
|
||||
}
|
27
feature-tests/no-alloc/tests/no_alloc.rs
Normal file
27
feature-tests/no-alloc/tests/no_alloc.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// This sub-crate exists to make sure that everything works well with the `no_alloc` flag enabled
|
||||
use core::fmt::Write;
|
||||
|
||||
use humansize::{Formatter, DECIMAL};
|
||||
|
||||
|
||||
struct Buffer<const N: usize>([u8; N], usize);
|
||||
|
||||
impl<const N: usize> Write for Buffer<N> {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
let space_left = self.0.len() - self.1;
|
||||
if space_left >= s.len() {
|
||||
self.0[self.1..][..s.len()].copy_from_slice(s.as_bytes());
|
||||
self.1 += s.len();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(core::fmt::Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut result = Buffer([0u8; 4], 0);
|
||||
write!(&mut result, "{}", Formatter::new(1000usize, DECIMAL)).unwrap();
|
||||
assert_eq!(core::str::from_utf8(&result.0).unwrap(), "1 kB");
|
||||
}
|
|
@ -1,16 +1,13 @@
|
|||
use alloc::string::String;
|
||||
|
||||
use crate::options::FormatSizeOptions;
|
||||
use crate::numeric_traits::*;
|
||||
use crate::options::FormatSizeOptions;
|
||||
use crate::IFormatter;
|
||||
|
||||
pub fn format_size_i(input: impl ToF64, options: impl AsRef<FormatSizeOptions>) -> String {
|
||||
format!(
|
||||
"{}",
|
||||
IFormatter {
|
||||
value: input,
|
||||
options
|
||||
}
|
||||
IFormatter::new(input, options)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
95
src/formatters.rs
Normal file
95
src/formatters.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use libm::{fabs, modf};
|
||||
|
||||
use crate::{ToF64, FormatSizeOptions, Kilo, BaseUnit, Unsigned, scales, utils::f64_eq};
|
||||
|
||||
pub struct IFormatter<T: ToF64, O: AsRef<FormatSizeOptions>> {
|
||||
value: T,
|
||||
options: O,
|
||||
}
|
||||
|
||||
impl<V: ToF64, O: AsRef<FormatSizeOptions>> IFormatter<V, O> {
|
||||
pub fn new(value: V, options: O) -> Self {
|
||||
IFormatter { value, options }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToF64, O: AsRef<FormatSizeOptions>> core::fmt::Display for IFormatter<T, O> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
let opts = self.options.as_ref();
|
||||
let divider = opts.kilo.value();
|
||||
|
||||
let mut size: f64 = self.value.to_f64();
|
||||
let mut scale_idx = 0;
|
||||
|
||||
if let Some(val) = opts.fixed_at {
|
||||
while scale_idx != val as usize {
|
||||
size /= divider;
|
||||
scale_idx += 1;
|
||||
}
|
||||
} else {
|
||||
while fabs(size) >= divider {
|
||||
size /= divider;
|
||||
scale_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut scale = match (opts.units, opts.long_units, opts.base_unit) {
|
||||
(Kilo::Decimal, false, BaseUnit::Byte) => scales::SCALE_DECIMAL[scale_idx],
|
||||
(Kilo::Decimal, true, BaseUnit::Byte) => scales::SCALE_DECIMAL_LONG[scale_idx],
|
||||
(Kilo::Binary, false, BaseUnit::Byte) => scales::SCALE_BINARY[scale_idx],
|
||||
(Kilo::Binary, true, BaseUnit::Byte) => scales::SCALE_BINARY_LONG[scale_idx],
|
||||
(Kilo::Decimal, false, BaseUnit::Bit) => scales::SCALE_DECIMAL_BIT[scale_idx],
|
||||
(Kilo::Decimal, true, BaseUnit::Bit) => scales::SCALE_DECIMAL_BIT_LONG[scale_idx],
|
||||
(Kilo::Binary, false, BaseUnit::Bit) => scales::SCALE_BINARY_BIT[scale_idx],
|
||||
(Kilo::Binary, true, BaseUnit::Bit) => scales::SCALE_BINARY_BIT_LONG[scale_idx],
|
||||
};
|
||||
|
||||
// Remove "s" from the scale if the size is 1.x
|
||||
let (fpart, ipart) = modf(size);
|
||||
if f64_eq(ipart, 1.0)
|
||||
&& (opts.long_units || (opts.base_unit == BaseUnit::Bit && scale_idx == 0))
|
||||
{
|
||||
scale = &scale[0..scale.len() - 1];
|
||||
}
|
||||
|
||||
let places = if f64_eq(fpart, 0.0) {
|
||||
opts.decimal_zeroes
|
||||
} else {
|
||||
opts.decimal_places
|
||||
};
|
||||
|
||||
let space = if opts.space_after_value { " " } else { "" };
|
||||
|
||||
write!(f, "{:.*}{}{}{}", places, size, space, scale, opts.suffix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, U: ToF64 + Unsigned + Copy, O: AsRef<FormatSizeOptions>> From<&'a Formatter<U, O>>
|
||||
for IFormatter<U, &'a O>
|
||||
{
|
||||
fn from(source: &'a Formatter<U, O>) -> Self {
|
||||
IFormatter {
|
||||
value: source.value,
|
||||
options: &source.options,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Formatter<T: ToF64 + Unsigned, O: AsRef<FormatSizeOptions>> {
|
||||
value: T,
|
||||
options: O,
|
||||
}
|
||||
|
||||
impl<V: ToF64 + Unsigned, O: AsRef<FormatSizeOptions>> Formatter<V, O> {
|
||||
pub fn new(value: V, options: O) -> Self {
|
||||
Formatter { value, options }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToF64 + Unsigned + Copy, O: AsRef<FormatSizeOptions> + Copy> core::fmt::Display
|
||||
for Formatter<T, O>
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "{}", IFormatter::from(self))
|
||||
}
|
||||
}
|
23
src/impl_style.rs
Normal file
23
src/impl_style.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
use alloc::string::String;
|
||||
use crate::{IFormatter, Formatter, FormatSizeOptions, ToF64, Unsigned, Signed};
|
||||
|
||||
pub trait FormatSize<T> {
|
||||
fn format_size(&self, opts: FormatSizeOptions) -> String;
|
||||
}
|
||||
|
||||
pub trait FormatSizeI<T> {
|
||||
fn format_size_i(&self, opts: FormatSizeOptions) -> String;
|
||||
}
|
||||
|
||||
impl<T: ToF64 + Unsigned + Copy> FormatSize<T> for T {
|
||||
fn format_size(&self, opts: FormatSizeOptions) -> String {
|
||||
format!("{}", Formatter::new(*self, opts))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToF64 + Signed + Copy> FormatSizeI<T> for T {
|
||||
fn format_size_i(&self, opts: FormatSizeOptions) -> String {
|
||||
format!("{}", IFormatter::new(*self, opts))
|
||||
}
|
||||
}
|
238
src/lib.rs
238
src/lib.rs
|
@ -2,36 +2,114 @@
|
|||
/*!
|
||||
# **Humansize**
|
||||
|
||||
Humansize lets you easily represent file sizes in a human-friendly format.
|
||||
You can specify your own formatting style, pick among the three defaults provided
|
||||
by the library:
|
||||
## Features
|
||||
Humansize is a humanization library for information size that is:
|
||||
- Simple & convenient to use
|
||||
- Customizable
|
||||
- Supports byte or bit sizes
|
||||
- `no-std`
|
||||
- Optionally non-allocating
|
||||
- Optionally accepts signed values
|
||||
|
||||
* Decimal (kilo = 1000, unit format is `kB`)
|
||||
* Binary (kilo = 1024, unit format is `KiB`)
|
||||
* Windows/Conventional (kilo = 1024, unit format is `kB`)
|
||||
## How to use it...
|
||||
|
||||
## How to use it
|
||||
|
||||
Simply import the `FileSize` trait and the options module and call the
|
||||
file_size method on any positive integer, using one of the three standards
|
||||
provided by the options module.
|
||||
|
||||
```rust
|
||||
extern crate humansize;
|
||||
use humansize::format_size;
|
||||
|
||||
fn main() {
|
||||
let size = 1000usize;
|
||||
println!("Size is {}", format_size(size, humansize::DECIMAL));
|
||||
|
||||
println!("Size is {}", format_size(size, humansize::BINARY));
|
||||
|
||||
println!("Size is {}", format_size(size, humansize::CONVENTIONAL));
|
||||
}
|
||||
Add humansize as a dependency to your project's `cargo.toml`:
|
||||
```toml
|
||||
[dependencies]
|
||||
...
|
||||
humansize = "2.0.0"
|
||||
```
|
||||
|
||||
If you wish to customize the way sizes are displayed, you may create your own custom `FormatSizeOptions` struct
|
||||
and pass that to the method. See the `custom_options.rs` file in the example folder.
|
||||
### ... to easily format a size:
|
||||
|
||||
1. Import the `format_size` function as well as your preferred set of defaults:
|
||||
- `DECIMAL` (SI)
|
||||
- `BINARY` (IEC)
|
||||
- `WINDOWS` (IEC values but SI units)
|
||||
2. Call `format_size` with an unsigned integer
|
||||
|
||||
```rust
|
||||
use humansize::{format_size, DECIMAL};
|
||||
|
||||
let size = 1_000_000u64;
|
||||
let res: String = format_size(size, DECIMAL);
|
||||
|
||||
assert_eq!(&res, "1 MB");
|
||||
|
||||
```
|
||||
|
||||
### ... to format many sizes:
|
||||
To improve reusability, you can use `create_format`, which returns a formatter function akin to `format_size` but with the options argument curried so it doesn't need to be specified again:
|
||||
|
||||
```rust
|
||||
use humansize::{make_format, DECIMAL};
|
||||
|
||||
let formatter = make_format(DECIMAL);
|
||||
|
||||
assert_eq!(formatter(1_000_000u64), "1 MB");
|
||||
assert_eq!(formatter(1_000_000_000u64), "1 GB");
|
||||
//...
|
||||
|
||||
```
|
||||
|
||||
### ... to avoid allocation:
|
||||
Specify the `no_alloc` feature flag in your project's `cargo.toml`:
|
||||
```toml
|
||||
[dependencies]
|
||||
...
|
||||
humansize = { version = "2.0.0", features = ["no_alloc"] }
|
||||
```
|
||||
This excludes all allocating code from compilation. You may now use the library's internal `Formatter` struct, which implements `core::fmt::display` so that you can `write!` it to a custom buffer of your choice:
|
||||
```rust
|
||||
use humansize::{IFormatter, DECIMAL};
|
||||
|
||||
let formatter = IFormatter::new(1_000_000, DECIMAL);
|
||||
assert_eq!(format!("{}", formatter), "1 MB");
|
||||
```
|
||||
### ... with the `impl` style API:
|
||||
For stylistic reasons, you may prefer to use the impl-style API of earlier versions of the crate.
|
||||
To do so, specify the `impl-style` feature flag in your project's `cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
...
|
||||
humansize = { version = "2.0.0", features = ["impl_style"] }
|
||||
```
|
||||
Enabling this feature makes two methods available:
|
||||
- `format_size` on unsigned integers types
|
||||
- `format_size_i` on signed integer types.
|
||||
|
||||
To use it, bring the FormatSize trait into scope and call its method on an integer type:
|
||||
```ignore
|
||||
use humansize::{FormatSize, FormatSizeI DECIMAL};
|
||||
|
||||
assert_eq!(1_000_000u64.format_size(DECIMAL), "1 MB");
|
||||
assert_eq!((-1_000_000).format_size_i(DECIMAL), "-1 MB");
|
||||
```
|
||||
### ... to further customize the output:
|
||||
Humansize exports three default option sets:
|
||||
* `Decimal`: kilo = 1000, unit format is `XB`.
|
||||
* `Binary`: kilo = 1024, unit format is `XiB`.
|
||||
* `WINDOWS` (Windows): kilo = 1024, unit format is `XB`.
|
||||
|
||||
The formatting can be further customized by providing providing your own option set. See the documentation of the `FormatSizeOptions` struct to see all the addressable parameters, and [this example](examples/custom_options.rs) for its usage.
|
||||
|
||||
### ... to accept negative values:
|
||||
The solutions presented above only accept unsigned integer types as input (`usize`, `8`, `u16`, `u32` and `u64`). If however accepting negative values is correct for your application, a signed alternative exists for each of them that will accept signed integer types, and format them accordingly if negative:
|
||||
|
||||
- `format_size` : `format_size_i`
|
||||
- `create_format` : `create_format_i`
|
||||
- `FormatSize` trait : `FormatSizeI` trait
|
||||
- `SizeFormatter` : `ISizeFormatter`
|
||||
```rust
|
||||
use humansize::{format_size_i, make_format_i, DECIMAL};
|
||||
|
||||
assert_eq!(&format_size_i(-1_000_000, DECIMAL), "-1 MB");
|
||||
|
||||
let signed_formatter = make_format_i(DECIMAL);
|
||||
assert_eq!(&signed_formatter(-1_000_000), "-1 MB");
|
||||
|
||||
```
|
||||
*/
|
||||
|
||||
#[macro_use]
|
||||
|
@ -39,110 +117,24 @@ and pass that to the method. See the `custom_options.rs` file in the example fol
|
|||
extern crate alloc;
|
||||
extern crate libm;
|
||||
|
||||
use core::f64;
|
||||
use libm::{fabs, modf};
|
||||
|
||||
mod options;
|
||||
pub use options::{FixedAt, FormatSizeOptions, Kilo, BINARY, CONVENTIONAL, DECIMAL};
|
||||
pub use options::{BaseUnit, FixedAt, FormatSizeOptions, Kilo, BINARY, WINDOWS, DECIMAL};
|
||||
|
||||
mod scales;
|
||||
mod numeric_traits;
|
||||
use numeric_traits::{ToF64, Unsigned};
|
||||
pub use numeric_traits::{ToF64, Unsigned, Signed};
|
||||
|
||||
mod utils;
|
||||
mod scales;
|
||||
|
||||
#[cfg(not(feature = "no_alloc"))]
|
||||
mod allocating;
|
||||
#[cfg(not(feature = "no_alloc"))]
|
||||
pub use allocating::*;
|
||||
|
||||
fn f64_eq(left: f64, right: f64) -> bool {
|
||||
left == right || fabs(left - right) <= f64::EPSILON
|
||||
}
|
||||
#[cfg(feature = "impl_style")]
|
||||
mod impl_style;
|
||||
#[cfg(feature = "impl_style")]
|
||||
pub use impl_style::{FormatSize, FormatSizeI};
|
||||
|
||||
pub struct IFormatter<T: ToF64, O: AsRef<FormatSizeOptions>> {
|
||||
pub value: T,
|
||||
pub options: O,
|
||||
}
|
||||
|
||||
impl<V: ToF64, O: AsRef<FormatSizeOptions>> IFormatter<V, O> {
|
||||
pub fn new(value: V, options: O) -> Self {
|
||||
IFormatter { value, options }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToF64, O: AsRef<FormatSizeOptions>> core::fmt::Display for IFormatter<T, O> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
let opts = self.options.as_ref();
|
||||
let divider = opts.kilo.value();
|
||||
|
||||
let mut size: f64 = self.value.to_f64();
|
||||
let mut scale_idx = 0;
|
||||
|
||||
match opts.fixed_at {
|
||||
FixedAt::No => {
|
||||
while fabs(size) >= divider {
|
||||
size /= divider;
|
||||
scale_idx += 1;
|
||||
}
|
||||
}
|
||||
val => {
|
||||
while scale_idx != val as usize {
|
||||
size /= divider;
|
||||
scale_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut scale = match (opts.units, opts.long_units) {
|
||||
(Kilo::Decimal, false) => scales::SCALE_DECIMAL[scale_idx],
|
||||
(Kilo::Decimal, true) => scales::SCALE_DECIMAL_LONG[scale_idx],
|
||||
(Kilo::Binary, false) => scales::SCALE_BINARY[scale_idx],
|
||||
(Kilo::Binary, true) => scales::SCALE_BINARY_LONG[scale_idx],
|
||||
};
|
||||
|
||||
// Remove "s" from the scale if the size is 1.x
|
||||
let (fpart, ipart) = modf(size);
|
||||
if opts.long_units && f64_eq(ipart, 1.0) {
|
||||
scale = &scale[0..scale.len() - 1];
|
||||
}
|
||||
|
||||
let places = if f64_eq(fpart, 0.0) {
|
||||
opts.decimal_zeroes
|
||||
} else {
|
||||
opts.decimal_places
|
||||
};
|
||||
|
||||
let space = if opts.space { " " } else { "" };
|
||||
|
||||
write!(f, "{:.*}{}{}{}", places, size, space, scale, opts.suffix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, U: ToF64 + Unsigned + Copy, O: AsRef<FormatSizeOptions>> From<&'a Formatter<U, O>>
|
||||
for IFormatter<U, &'a O>
|
||||
{
|
||||
fn from(source: &'a Formatter<U, O>) -> Self {
|
||||
IFormatter {
|
||||
value: source.value,
|
||||
options: &source.options,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Formatter<T: ToF64 + Unsigned, O: AsRef<FormatSizeOptions>> {
|
||||
value: T,
|
||||
options: O,
|
||||
}
|
||||
|
||||
impl<V: ToF64 + Unsigned, O: AsRef<FormatSizeOptions>> Formatter<V, O> {
|
||||
pub fn new(value: V, options: O) -> Self {
|
||||
Formatter { value, options }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToF64 + Unsigned + Copy, O: AsRef<FormatSizeOptions> + Copy> core::fmt::Display
|
||||
for Formatter<T, O>
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "{}", IFormatter::from(self))
|
||||
}
|
||||
}
|
||||
mod formatters;
|
||||
pub use formatters::{Formatter, IFormatter};
|
||||
|
|
|
@ -23,3 +23,14 @@ macro_rules! impl_unsigned {
|
|||
}
|
||||
|
||||
impl_unsigned!(for usize u8 u16 u32 u64);
|
||||
|
||||
|
||||
pub trait Signed {}
|
||||
|
||||
macro_rules! impl_unsigned {
|
||||
(for $($t:ty)*) => ($(
|
||||
impl Signed for $t {}
|
||||
)*)
|
||||
}
|
||||
|
||||
impl_unsigned!(for isize i8 i16 i32 i64);
|
||||
|
|
|
@ -1,38 +1,41 @@
|
|||
use super::{FixedAt, FormatSizeOptions, Kilo};
|
||||
use super::{BaseUnit, FormatSizeOptions, Kilo};
|
||||
|
||||
/// Options to display sizes in the SI format.
|
||||
pub const BINARY: FormatSizeOptions = FormatSizeOptions {
|
||||
base_unit: BaseUnit::Byte,
|
||||
kilo: Kilo::Binary,
|
||||
units: Kilo::Binary,
|
||||
decimal_places: 2,
|
||||
decimal_zeroes: 0,
|
||||
fixed_at: FixedAt::No,
|
||||
fixed_at: None,
|
||||
long_units: false,
|
||||
space: true,
|
||||
space_after_value: true,
|
||||
suffix: "",
|
||||
};
|
||||
|
||||
/// Options to display sizes in the SI (decimal) format.
|
||||
pub const DECIMAL: FormatSizeOptions = FormatSizeOptions {
|
||||
base_unit: BaseUnit::Byte,
|
||||
kilo: Kilo::Decimal,
|
||||
units: Kilo::Decimal,
|
||||
decimal_places: 2,
|
||||
decimal_zeroes: 0,
|
||||
fixed_at: FixedAt::No,
|
||||
fixed_at: None,
|
||||
long_units: false,
|
||||
space: true,
|
||||
space_after_value: true,
|
||||
suffix: "",
|
||||
};
|
||||
|
||||
/// Options to display sizes in the "conventional" format.
|
||||
/// This 1024 as the value of the `Kilo`, but displays decimal-style units (`kB`, not `KiB`).
|
||||
pub const CONVENTIONAL: FormatSizeOptions = FormatSizeOptions {
|
||||
/// Options to display sizes in the "WINDOWS" format.
|
||||
/// Uses 1024 as the value of the `Kilo`, but displays decimal-style units (`kB`, not `KiB`).
|
||||
pub const WINDOWS: FormatSizeOptions = FormatSizeOptions {
|
||||
base_unit: BaseUnit::Byte,
|
||||
kilo: Kilo::Binary,
|
||||
units: Kilo::Decimal,
|
||||
decimal_places: 2,
|
||||
decimal_zeroes: 0,
|
||||
fixed_at: FixedAt::No,
|
||||
fixed_at: None,
|
||||
long_units: false,
|
||||
space: true,
|
||||
space_after_value: true,
|
||||
suffix: "",
|
||||
};
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
//! Describes the struct that holds the options needed by the `file_size` method.
|
||||
//! Describes the struct that holds the options needed by the formatting functions.
|
||||
//! The three most common formats are provided as constants to be used easily
|
||||
|
||||
mod defaults;
|
||||
pub use self::defaults::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
|
||||
/// Holds the standard to use when displaying the size.
|
||||
pub enum Kilo {
|
||||
/// The decimal scale and units. SI standard.
|
||||
#[default]
|
||||
Decimal,
|
||||
/// The binary scale and units
|
||||
/// The binary scale and units.
|
||||
Binary,
|
||||
}
|
||||
|
||||
|
@ -25,7 +26,7 @@ impl Kilo {
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
/// Forces a certain representation of the resulting file size.
|
||||
pub enum FixedAt {
|
||||
Byte,
|
||||
Base,
|
||||
Kilo,
|
||||
Mega,
|
||||
Giga,
|
||||
|
@ -34,12 +35,22 @@ pub enum FixedAt {
|
|||
Exa,
|
||||
Zetta,
|
||||
Yotta,
|
||||
No,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Default)]
|
||||
pub enum BaseUnit {
|
||||
Bit,
|
||||
#[default]
|
||||
Byte,
|
||||
}
|
||||
|
||||
/// Holds the options for the `file_size` method.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FormatSizeOptions {
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct FormatSizeOptionsBuilder {
|
||||
/// Whether the value being formatted represents an amount of bits or bytes.
|
||||
pub base_unit: BaseUnit,
|
||||
|
||||
/// The scale (binary/decimal) to divide against.
|
||||
pub kilo: Kilo,
|
||||
|
||||
|
@ -53,18 +64,101 @@ pub struct FormatSizeOptions {
|
|||
pub decimal_zeroes: usize,
|
||||
|
||||
/// Whether to force a certain representation and if so, which one.
|
||||
pub fixed_at: FixedAt,
|
||||
pub fixed_at: Option<FixedAt>,
|
||||
|
||||
/// Whether to use the full unit (e.g. `Kilobyte`) or its abbreviation (`kB`).
|
||||
pub long_units: bool,
|
||||
|
||||
/// Whether to place a space between value and units.
|
||||
pub space: bool,
|
||||
pub space_after_value: bool,
|
||||
|
||||
/// An optional suffix which will be appended after the unit. Useful to represent speeds (e.g. `1 kB/s)
|
||||
pub suffix: &'static str,
|
||||
}
|
||||
|
||||
/// Holds the options for the `file_size` method.
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct FormatSizeOptions {
|
||||
/// Whether the value being formatted represents an amount of bits or bytes.
|
||||
pub base_unit: BaseUnit,
|
||||
|
||||
/// The scale (binary/decimal) to divide against.
|
||||
pub kilo: Kilo,
|
||||
|
||||
/// The unit set to display.
|
||||
pub units: Kilo,
|
||||
|
||||
/// The amount of decimal places to display if the decimal part is non-zero.
|
||||
pub decimal_places: usize,
|
||||
|
||||
/// The amount of zeroes to display if the decimal part is zero.
|
||||
pub decimal_zeroes: usize,
|
||||
|
||||
/// Whether to force a certain representation and if so, which one.
|
||||
pub fixed_at: Option<FixedAt>,
|
||||
|
||||
/// Whether to use the full unit (e.g. `Kilobyte`) or its abbreviation (`kB`).
|
||||
pub long_units: bool,
|
||||
|
||||
/// Whether to place a space between value and units.
|
||||
pub space_after_value: bool,
|
||||
|
||||
/// An optional suffix which will be appended after the unit. Useful to represent speeds (e.g. `1 kB/s)
|
||||
pub suffix: &'static str,
|
||||
}
|
||||
|
||||
impl FormatSizeOptions {
|
||||
pub fn from(from: FormatSizeOptions) -> FormatSizeOptions {
|
||||
FormatSizeOptions { ..from }
|
||||
}
|
||||
|
||||
pub fn base_unit(mut self, base_unit: BaseUnit) -> FormatSizeOptions {
|
||||
self.base_unit = base_unit;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kilo(mut self, kilo: Kilo) -> FormatSizeOptions {
|
||||
self.kilo = kilo;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn units(mut self, units: Kilo) -> FormatSizeOptions {
|
||||
self.units = units;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn decimal_places(mut self, decimal_places: usize) -> FormatSizeOptions {
|
||||
self.decimal_places = decimal_places;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn decimal_zeroes(mut self, decimal_zeroes: usize) -> FormatSizeOptions {
|
||||
self.decimal_zeroes = decimal_zeroes;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn fixed_at(mut self, fixed_at: Option<FixedAt>) -> FormatSizeOptions {
|
||||
self.fixed_at = fixed_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn long_units(mut self, long_units: bool) -> FormatSizeOptions {
|
||||
self.long_units = long_units;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn space_after_value(mut self, insert_space: bool) -> FormatSizeOptions {
|
||||
self.space_after_value = insert_space;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn suffix(mut self, suffix: &'static str) -> FormatSizeOptions {
|
||||
self.suffix = suffix;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<FormatSizeOptions> for FormatSizeOptions {
|
||||
fn as_ref(&self) -> &FormatSizeOptions {
|
||||
self
|
||||
|
|
|
@ -26,3 +26,28 @@ pub(crate) static SCALE_BINARY_LONG: [&str; 9] = [
|
|||
"Zebibytes",
|
||||
"Yobibytes",
|
||||
];
|
||||
|
||||
pub(crate) static SCALE_DECIMAL_BIT: [&str; 9] = [
|
||||
"bits", "kbit", "Mbit", "Gbit", "Tbit", "Pbit", "Ebit", "Zbit", "Ybit",
|
||||
];
|
||||
|
||||
pub(crate) static SCALE_DECIMAL_BIT_LONG: [&str; 9] = [
|
||||
"Bits",
|
||||
"Kilobits",
|
||||
"Megabits",
|
||||
"Gigabits",
|
||||
"Terabits",
|
||||
"Petabits",
|
||||
"Exabits",
|
||||
"Zettabits",
|
||||
"Yottabits",
|
||||
];
|
||||
|
||||
pub(crate) static SCALE_BINARY_BIT: [&str; 9] = [
|
||||
"bits", "Kibit", "Mibit", "Gibit", "Tibit", "Pibit", "Eibit", "Zibit", "Yibit",
|
||||
];
|
||||
|
||||
pub(crate) static SCALE_BINARY_BIT_LONG: [&str; 9] = [
|
||||
"bits", "Kibibits", "Mebibits", "Gibibits", "Tebibits", "Pebibits", "Exbibits", "Zebibits",
|
||||
"Yobibits",
|
||||
];
|
||||
|
|
5
src/utils.rs
Normal file
5
src/utils.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
use libm::fabs;
|
||||
|
||||
pub(crate) fn f64_eq(left: f64, right: f64) -> bool {
|
||||
left == right || fabs(left - right) <= f64::EPSILON
|
||||
}
|
100
tests/test.rs
100
tests/test.rs
|
@ -1,5 +1,5 @@
|
|||
use humansize::{
|
||||
format_size, format_size_i, FixedAt, FormatSizeOptions, BINARY, CONVENTIONAL, DECIMAL,
|
||||
format_size, format_size_i, BaseUnit, FixedAt, FormatSizeOptions, BINARY, WINDOWS, DECIMAL,
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
@ -11,82 +11,67 @@ fn test_sizes() {
|
|||
assert_eq!(format_size(1023u32, BINARY), "1023 B");
|
||||
assert_eq!(format_size(1023u32, DECIMAL), "1.02 kB");
|
||||
assert_eq!(format_size(1024u32, BINARY), "1 KiB");
|
||||
assert_eq!(format_size(1024u32, CONVENTIONAL), "1 kB");
|
||||
assert_eq!(format_size(1024u32, WINDOWS), "1 kB");
|
||||
|
||||
let semi_custom_options = FormatSizeOptions {
|
||||
space: false,
|
||||
..DECIMAL
|
||||
};
|
||||
assert_eq!(format_size(1000u32, semi_custom_options), "1kB");
|
||||
let custom_options = FormatSizeOptions::from(DECIMAL).space_after_value(false);
|
||||
assert_eq!(format_size(1000u32, custom_options), "1kB");
|
||||
|
||||
let semi_custom_options2 = FormatSizeOptions {
|
||||
suffix: "/s",
|
||||
..BINARY
|
||||
};
|
||||
assert_eq!(format_size(999u32, semi_custom_options2), "999 B/s");
|
||||
let custom_options = FormatSizeOptions::from(BINARY).suffix("/s");
|
||||
assert_eq!(format_size(999u32, custom_options), "999 B/s");
|
||||
|
||||
let semi_custom_options3 = FormatSizeOptions {
|
||||
suffix: "/day",
|
||||
space: false,
|
||||
..DECIMAL
|
||||
};
|
||||
assert_eq!(format_size(1000u32, semi_custom_options3), "1kB/day");
|
||||
let custom_options = FormatSizeOptions::from(DECIMAL).suffix("/day").space_after_value(false);
|
||||
assert_eq!(format_size(1000u32, custom_options), "1kB/day");
|
||||
|
||||
let semi_custom_options4 = FormatSizeOptions {
|
||||
fixed_at: FixedAt::Byte,
|
||||
..BINARY
|
||||
};
|
||||
assert_eq!(format_size(2048u32, semi_custom_options4), "2048 B");
|
||||
|
||||
let semi_custom_options5 = FormatSizeOptions {
|
||||
fixed_at: FixedAt::Kilo,
|
||||
..BINARY
|
||||
};
|
||||
let custom_options = FormatSizeOptions::from(BINARY).fixed_at(Some(FixedAt::Base));
|
||||
assert_eq!(format_size(2048u32, custom_options), "2048 B");
|
||||
|
||||
|
||||
let custom_options = FormatSizeOptions::from(BINARY).fixed_at(Some(FixedAt::Base)).long_units(true);
|
||||
assert_eq!(format_size(2048u32, custom_options), "2048 Bytes");
|
||||
|
||||
|
||||
|
||||
let custom_options = FormatSizeOptions::from(BINARY).fixed_at(Some(FixedAt::Kilo));
|
||||
assert_eq!(
|
||||
format_size(16584975u32, semi_custom_options5),
|
||||
format_size(16584975u32, custom_options),
|
||||
"16196.26 KiB"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format_size_i(-16584975, semi_custom_options5),
|
||||
format_size_i(-16584975, custom_options),
|
||||
"-16196.26 KiB"
|
||||
);
|
||||
|
||||
let semi_custom_options6 = FormatSizeOptions {
|
||||
fixed_at: FixedAt::Tera,
|
||||
decimal_places: 10,
|
||||
..BINARY
|
||||
};
|
||||
|
||||
|
||||
let custom_options = FormatSizeOptions::from(BINARY).fixed_at(Some(FixedAt::Tera)).decimal_places(10);
|
||||
assert_eq!(
|
||||
format_size(15284975u32, semi_custom_options6),
|
||||
format_size(15284975u32, custom_options),
|
||||
"0.0000139016 TiB"
|
||||
);
|
||||
|
||||
let semi_custom_options7 = FormatSizeOptions { ..DECIMAL };
|
||||
assert_eq!((format_size_i(-5500, &semi_custom_options7)), "-5.50 kB");
|
||||
assert_eq!((format_size(5500u32, &semi_custom_options7)), "5.50 kB");
|
||||
assert_eq!((format_size_i(-5500, DECIMAL)), "-5.50 kB");
|
||||
assert_eq!((format_size(5500u32, DECIMAL)), "5.50 kB");
|
||||
|
||||
|
||||
let custom_options = FormatSizeOptions::from(DECIMAL).base_unit(BaseUnit::Bit);
|
||||
assert_eq!((format_size(1usize, custom_options)), "1 bit");
|
||||
assert_eq!((format_size(150usize, custom_options)), "150 bits");
|
||||
assert_eq!((format_size(1000usize, custom_options)), "1 kbit");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_custom_option_struct_twice() {
|
||||
let options = FormatSizeOptions {
|
||||
long_units: true,
|
||||
..DECIMAL
|
||||
};
|
||||
let options = FormatSizeOptions::from(DECIMAL).long_units(true);
|
||||
|
||||
assert_eq!(format_size(1500u32, &options), "1.50 Kilobyte",);
|
||||
|
||||
assert_eq!(format_size(2500u32, &options), "2.50 Kilobytes",);
|
||||
assert_eq!(format_size_i(-2500000, &options), "-2.50 Megabytes",);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pluralization_works() {
|
||||
let options = FormatSizeOptions {
|
||||
long_units: true,
|
||||
decimal_zeroes: 2,
|
||||
..DECIMAL
|
||||
};
|
||||
let options = FormatSizeOptions::from(DECIMAL).long_units(true).decimal_zeroes(2);
|
||||
|
||||
assert_eq!(format_size(1u32, &options), "1.00 Byte",);
|
||||
|
||||
|
@ -111,22 +96,13 @@ fn pluralization_works() {
|
|||
|
||||
#[test]
|
||||
fn max_value_decimal() {
|
||||
let options = FormatSizeOptions {
|
||||
long_units: true,
|
||||
decimal_places: 7,
|
||||
..DECIMAL
|
||||
};
|
||||
|
||||
assert_eq!(format_size(std::u64::MAX, &options), "18.4467441 Exabytes",);
|
||||
let options = FormatSizeOptions::from(DECIMAL).decimal_places(7).long_units(true);
|
||||
assert_eq!(format_size(core::u64::MAX, &options), "18.4467441 Exabytes",);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_value_binary() {
|
||||
let options = FormatSizeOptions {
|
||||
long_units: true,
|
||||
decimal_places: 7,
|
||||
..BINARY
|
||||
};
|
||||
let options = FormatSizeOptions::from(BINARY).decimal_places(7).long_units(true);
|
||||
|
||||
assert_eq!(format_size(std::u64::MAX, &options), "16 Exbibytes",);
|
||||
assert_eq!(format_size(core::u64::MAX, &options), "16 Exbibytes",);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue