Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix inverted SI / IEC conditions #69

Merged
merged 9 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## Unreleased

- Use SI format by default with `Display`.
- Use "KiB" for SI unit.
- Use IEC (binary) format by default with `Display`.
- Use "kB" for SI unit.
- Implement `Sub<ByteSize>` for `ByteSize`.
- Implement `Sub<impl Into<u64>>` for `ByteSize`.
- Implement `SubAssign<ByteSize>` for `ByteSize`.
Expand Down
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
name = "bytesize"
description = "A utility for human-readable byte count representations"
version = "1.3.0"
authors = ["Hyunsik Choi <hyunsik.choi@gmail.com>", "MrCroxx <mrcroxx@outlook.com>"]
authors = [
"Hyunsik Choi <hyunsik.choi@gmail.com>",
"MrCroxx <mrcroxx@outlook.com>",
"Rob Ede <robjtede@icloud.com>",
]
keywords = ["byte", "byte-size", "utility", "human-readable", "format"]
categories = ["development-tools", "filesystem"]
repository = "https://github.com/bytesize-rs/bytesize"
Expand Down
108 changes: 70 additions & 38 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
//! ```
//! use bytesize::ByteSize;
//!
//! assert_eq!("482.4 GiB", ByteSize::gb(518).to_string_as(true));
//! assert_eq!("518.0 GB", ByteSize::gb(518).to_string_as(false));
//! assert_eq!("482.4 GiB", ByteSize::gb(518).to_string_as(false));
//! assert_eq!("518.0 GB", ByteSize::gb(518).to_string_as(true));
Comment on lines +26 to +27
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rust doc also needs to be updated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will be, this fn still exists for now

//! ```

mod parse;
Expand Down Expand Up @@ -58,10 +58,28 @@ pub const TIB: u64 = 1_099_511_627_776;
/// bytes size for 1 pebibyte
pub const PIB: u64 = 1_125_899_906_842_624;

static UNITS: &str = "KMGTPE";
static UNITS_SI: &str = "KMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000
/// IEC (binary) units.
///
/// See <https://en.wikipedia.org/wiki/Kilobyte>.
const UNITS_IEC: &str = "KMGTPE";

/// SI (decimal) units.
///
/// See <https://en.wikipedia.org/wiki/Kilobyte>.
const UNITS_SI: &str = "kMGTPE";

/// `ln(1024) ~= 6.931`
const LN_KIB: f64 = 6.931_471_805_599_453;

/// `ln(1000) ~= 6.908`
const LN_KB: f64 = 6.907_755_278_982_137;

#[derive(Debug, Clone, Default)]
pub enum Format {
#[default]
IEC,
SI,
}
Comment on lines +77 to +82
Copy link
Member Author

@robjtede robjtede Feb 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this enum may or may not stay public (i have an idea to present in a follow up PR) but it really makes this PR easier to reason about


pub fn kb<V: Into<u64>>(size: V) -> u64 {
size.into() * KB
Expand Down Expand Up @@ -175,15 +193,28 @@ impl ByteSize {
}
}

pub fn to_string(bytes: u64, si_prefix: bool) -> String {
let unit = if si_prefix { KIB } else { KB };
let unit_base = if si_prefix { LN_KIB } else { LN_KB };
let unit_prefix = if si_prefix {
UNITS_SI.as_bytes()
} else {
UNITS.as_bytes()
pub fn to_string(bytes: u64, si_unit: bool) -> String {
to_string_format(bytes, if si_unit { Format::SI } else { Format::IEC })
}

pub fn to_string_format(bytes: u64, format: Format) -> String {
let unit = match format {
Format::IEC => KIB,
Format::SI => KB,
};
let unit_base = match format {
Format::IEC => LN_KIB,
Format::SI => LN_KB,
};

let unit_prefix = match format {
Format::IEC => UNITS_IEC.as_bytes(),
Format::SI => UNITS_SI.as_bytes(),
};
let unit_suffix = match format {
Format::IEC => "iB",
Format::SI => "B",
};
let unit_suffix = if si_prefix { "iB" } else { "B" };

if bytes < unit {
format!("{} B", bytes)
Expand All @@ -205,13 +236,13 @@ pub fn to_string(bytes: u64, si_prefix: bool) -> String {

impl Display for ByteSize {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(&to_string(self.0, true))
f.pad(&to_string_format(self.0, Format::IEC))
}
}

impl Debug for ByteSize {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self)
<Self as Display>::fmt(self, f)
}
}

Expand Down Expand Up @@ -395,6 +426,7 @@ mod tests {
assert!(ByteSize::b(0) < ByteSize::tib(1));
}

#[track_caller]
fn assert_display(expected: &str, b: ByteSize) {
assert_eq!(expected, format!("{}", b));
}
Expand Down Expand Up @@ -422,39 +454,39 @@ mod tests {
assert_eq!("|--357 B---|", format!("|{:-^10}|", ByteSize(357)));
}

fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
assert_eq!(expected.to_string(), b.to_string_as(si));
#[track_caller]
fn assert_to_string(expected: &str, b: ByteSize, format: Format) {
assert_eq!(expected.to_string(), to_string_format(b.0, format));
}

#[test]
fn test_to_string_as() {
assert_to_string("215 B", ByteSize::b(215), true);
assert_to_string("215 B", ByteSize::b(215), false);
assert_to_string("215 B", ByteSize::b(215), Format::IEC);
assert_to_string("215 B", ByteSize::b(215), Format::SI);

assert_to_string("1.0 KiB", ByteSize::kib(1), true);
assert_to_string("1.0 KB", ByteSize::kib(1), false);
assert_to_string("1.0 KiB", ByteSize::kib(1), Format::IEC);
assert_to_string("1.0 kB", ByteSize::kib(1), Format::SI);

assert_to_string("293.9 KiB", ByteSize::kb(301), true);
assert_to_string("301.0 KB", ByteSize::kb(301), false);
assert_to_string("293.9 KiB", ByteSize::kb(301), Format::IEC);
assert_to_string("301.0 kB", ByteSize::kb(301), Format::SI);

assert_to_string("1.0 MiB", ByteSize::mib(1), true);
assert_to_string("1048.6 KB", ByteSize::mib(1), false);
assert_to_string("1.0 MiB", ByteSize::mib(1), Format::IEC);
assert_to_string("1.0 MB", ByteSize::mib(1), Format::SI);

// a bug case: https://github.com/flang-project/bytesize/issues/8
assert_to_string("1.9 GiB", ByteSize::mib(1907), true);
assert_to_string("2.0 GB", ByteSize::mib(1908), false);
assert_to_string("1.9 GiB", ByteSize::mib(1907), Format::IEC);
assert_to_string("2.0 GB", ByteSize::mib(1908), Format::SI);

assert_to_string("399.6 MiB", ByteSize::mb(419), true);
assert_to_string("419.0 MB", ByteSize::mb(419), false);
assert_to_string("399.6 MiB", ByteSize::mb(419), Format::IEC);
assert_to_string("419.0 MB", ByteSize::mb(419), Format::SI);

assert_to_string("482.4 GiB", ByteSize::gb(518), true);
assert_to_string("518.0 GB", ByteSize::gb(518), false);
assert_to_string("482.4 GiB", ByteSize::gb(518), Format::IEC);
assert_to_string("518.0 GB", ByteSize::gb(518), Format::SI);

assert_to_string("741.2 TiB", ByteSize::tb(815), true);
assert_to_string("815.0 TB", ByteSize::tb(815), false);
assert_to_string("741.2 TiB", ByteSize::tb(815), Format::IEC);
assert_to_string("815.0 TB", ByteSize::tb(815), Format::SI);

assert_to_string("540.9 PiB", ByteSize::pb(609), true);
assert_to_string("609.0 PB", ByteSize::pb(609), false);
assert_to_string("540.9 PiB", ByteSize::pb(609), Format::IEC);
assert_to_string("609.0 PB", ByteSize::pb(609), Format::SI);
}

#[test]
Expand All @@ -464,6 +496,6 @@ mod tests {

#[test]
fn test_to_string() {
assert_to_string("609.0 PB", ByteSize::pb(609), false);
assert_to_string("609.0 PB", ByteSize::pb(609), Format::SI);
}
}
6 changes: 4 additions & 2 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ impl std::str::FromStr for Unit {

#[cfg(test)]
mod tests {
use crate::to_string_format;

use super::*;

#[test]
Expand Down Expand Up @@ -234,8 +236,8 @@ mod tests {

assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GigaByte);
assert_eq!(
parse(&crate::to_string(parse("128.000 GiB"), true)),
128 * Unit::GibiByte
parse(&to_string_format(parse("128.000 GiB"), crate::Format::IEC)),
128 * Unit::GibiByte,
);
}
}
1 change: 0 additions & 1 deletion src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ mod tests {
}

#[test]

fn test_serde_json() {
let json = serde_json::to_string(&ByteSize::mib(1)).unwrap();
assert_eq!(json, "\"1.0 MiB\"");
Expand Down