use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ByteConversionStandard {
Binary, Decimal, }
pub trait ByteToGB {
fn to_gb(&self, standard: ByteConversionStandard) -> f64;
fn to_gb_binary(&self) -> f64;
fn to_gb_decimal(&self) -> f64;
fn format_bytes(&self) -> String;
}
impl ByteToGB for u64 {
fn to_gb(&self, standard: ByteConversionStandard) -> f64 {
match standard {
ByteConversionStandard::Binary => self.to_gb_binary(),
ByteConversionStandard::Decimal => self.to_gb_decimal(),
}
}
fn to_gb_binary(&self) -> f64 {
*self as f64 / 1024.0 / 1024.0 / 1024.0
}
fn to_gb_decimal(&self) -> f64 {
*self as f64 / 1000.0 / 1000.0 / 1000.0
}
fn format_bytes(&self) -> String {
const UNITS: [&str; 7] = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
let mut value = *self as f64;
let mut unit_index = 0;
while value >= 1024.0 && unit_index < UNITS.len() - 1 {
value /= 1024.0;
unit_index += 1;
}
format!("{:.2} {}", value, UNITS[unit_index])
}
}
impl fmt::Display for ByteConversionStandard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ByteConversionStandard::Binary => write!(f, "二进制 (IEC)"),
ByteConversionStandard::Decimal => write!(f, "十进制 (SI)"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_binary_conversion() {
let bytes: u64 = 1_073_741_824; assert!((bytes.to_gb_binary() - 1.0).abs() < 0.0001);
}
#[test]
fn test_decimal_conversion() {
let bytes: u64 = 1_000_000_000; assert!((bytes.to_gb_decimal() - 1.0).abs() < 0.0001);
}
#[test]
fn test_format_bytes() {
assert_eq!(1024.format_bytes(), "1.00 KB");
assert_eq!(1_500_000.format_bytes(), "1.43 MB");
assert_eq!(15_000_000_000.format_bytes(), "13.97 GB");
}
}