mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
df: refactor HumanReadable handling
The refactoring consists of three parts: 1) Introduction of SizeFormat & HumanReadable enums 2) Addition of a size_format field to the options struct 3) Movement of header logic from BlockSize to Header
This commit is contained in:
parent
f6b9d36891
commit
46e029f34c
3 changed files with 80 additions and 58 deletions
|
@ -3,7 +3,7 @@
|
|||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
//! Types for representing and displaying block sizes.
|
||||
use crate::{OPT_BLOCKSIZE, OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL};
|
||||
use crate::OPT_BLOCKSIZE;
|
||||
use clap::ArgMatches;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -117,14 +117,46 @@ fn to_magnitude_and_suffix(n: u128) -> Result<String, ()> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A mode to use in condensing the display of a large number of bytes.
|
||||
pub(crate) enum SizeFormat {
|
||||
HumanReadable(HumanReadable),
|
||||
StaticBlockSize,
|
||||
}
|
||||
|
||||
impl Default for SizeFormat {
|
||||
fn default() -> Self {
|
||||
Self::StaticBlockSize
|
||||
}
|
||||
}
|
||||
|
||||
/// A mode to use in condensing the human readable display of a large number
|
||||
/// of bytes.
|
||||
///
|
||||
/// The [`HumanReadable::Decimal`] and[`HumanReadable::Binary`] variants
|
||||
/// represent dynamic block sizes: as the number of bytes increases, the
|
||||
/// divisor increases as well (for example, from 1 to 1,000 to 1,000,000
|
||||
/// and so on in the case of [`HumanReadable::Decimal`]).
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum HumanReadable {
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,000. Contrast with
|
||||
/// [`HumanReadable::Binary`], which represents powers of
|
||||
/// 1,024.
|
||||
Decimal,
|
||||
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,024. Contrast with
|
||||
/// [`HumanReadable::Decimal`], which represents powers
|
||||
/// of 1,000.
|
||||
Binary,
|
||||
}
|
||||
|
||||
/// A block size to use in condensing the display of a large number of bytes.
|
||||
///
|
||||
/// The [`BlockSize::Bytes`] variant represents a static block
|
||||
/// size. The [`BlockSize::HumanReadableDecimal`] and
|
||||
/// [`BlockSize::HumanReadableBinary`] variants represent dynamic
|
||||
/// block sizes: as the number of bytes increases, the divisor
|
||||
/// increases as well (for example, from 1 to 1,000 to 1,000,000 and
|
||||
/// so on in the case of [`BlockSize::HumanReadableDecimal`]).
|
||||
/// size.
|
||||
///
|
||||
/// The default variant is `Bytes(1024)`.
|
||||
pub(crate) enum BlockSize {
|
||||
|
@ -132,20 +164,6 @@ pub(crate) enum BlockSize {
|
|||
///
|
||||
/// The number must be positive.
|
||||
Bytes(u64),
|
||||
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,000. Contrast with
|
||||
/// [`BlockSize::HumanReadableBinary`], which represents powers of
|
||||
/// 1,024.
|
||||
HumanReadableDecimal,
|
||||
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,024. Contrast with
|
||||
/// [`BlockSize::HumanReadableDecimal`], which represents powers
|
||||
/// of 1,000.
|
||||
HumanReadableBinary,
|
||||
}
|
||||
|
||||
impl Default for BlockSize {
|
||||
|
@ -155,11 +173,7 @@ impl Default for BlockSize {
|
|||
}
|
||||
|
||||
pub(crate) fn block_size_from_matches(matches: &ArgMatches) -> Result<BlockSize, ParseSizeError> {
|
||||
if matches.is_present(OPT_HUMAN_READABLE_BINARY) {
|
||||
Ok(BlockSize::HumanReadableBinary)
|
||||
} else if matches.is_present(OPT_HUMAN_READABLE_DECIMAL) {
|
||||
Ok(BlockSize::HumanReadableDecimal)
|
||||
} else if matches.is_present(OPT_BLOCKSIZE) {
|
||||
if matches.is_present(OPT_BLOCKSIZE) {
|
||||
let s = matches.value_of(OPT_BLOCKSIZE).unwrap();
|
||||
Ok(BlockSize::Bytes(parse_size(s)?))
|
||||
} else {
|
||||
|
@ -170,10 +184,8 @@ pub(crate) fn block_size_from_matches(matches: &ArgMatches) -> Result<BlockSize,
|
|||
impl fmt::Display for BlockSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::HumanReadableBinary => write!(f, "Size"),
|
||||
Self::HumanReadableDecimal => write!(f, "Size"),
|
||||
Self::Bytes(n) => match to_magnitude_and_suffix(*n as u128) {
|
||||
Ok(s) => write!(f, "{}-blocks", s),
|
||||
Ok(s) => write!(f, "{}", s),
|
||||
Err(_) => Err(fmt::Error),
|
||||
},
|
||||
}
|
||||
|
@ -229,13 +241,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_block_size_display() {
|
||||
assert_eq!(format!("{}", BlockSize::HumanReadableBinary), "Size");
|
||||
assert_eq!(format!("{}", BlockSize::HumanReadableDecimal), "Size");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(1024)), "1K-blocks");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(2 * 1024)), "2K-blocks");
|
||||
assert_eq!(
|
||||
format!("{}", BlockSize::Bytes(3 * 1024 * 1024)),
|
||||
"3M-blocks"
|
||||
);
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(1024)), "1K");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(2 * 1024)), "2K");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(3 * 1024 * 1024)), "3M");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ mod columns;
|
|||
mod filesystem;
|
||||
mod table;
|
||||
|
||||
use blocks::{HumanReadable, SizeFormat};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{UError, UResult, USimpleError};
|
||||
use uucore::fsext::{read_fs_list, MountInfo};
|
||||
|
@ -62,6 +63,7 @@ static OUTPUT_FIELD_LIST: [&str; 12] = [
|
|||
struct Options {
|
||||
show_local_fs: bool,
|
||||
show_all_fs: bool,
|
||||
size_format: SizeFormat,
|
||||
block_size: BlockSize,
|
||||
|
||||
/// Optional list of filesystem types to include in the output table.
|
||||
|
@ -89,6 +91,7 @@ impl Default for Options {
|
|||
show_local_fs: Default::default(),
|
||||
show_all_fs: Default::default(),
|
||||
block_size: Default::default(),
|
||||
size_format: Default::default(),
|
||||
include: Default::default(),
|
||||
exclude: Default::default(),
|
||||
show_total: Default::default(),
|
||||
|
@ -166,6 +169,15 @@ impl Options {
|
|||
),
|
||||
ParseSizeError::ParseFailure(s) => OptionsError::InvalidBlockSize(s),
|
||||
})?,
|
||||
size_format: {
|
||||
if matches.is_present(OPT_HUMAN_READABLE_BINARY) {
|
||||
SizeFormat::HumanReadable(HumanReadable::Binary)
|
||||
} else if matches.is_present(OPT_HUMAN_READABLE_DECIMAL) {
|
||||
SizeFormat::HumanReadable(HumanReadable::Decimal)
|
||||
} else {
|
||||
SizeFormat::StaticBlockSize
|
||||
}
|
||||
},
|
||||
include,
|
||||
exclude,
|
||||
show_total: matches.is_present(OPT_TOTAL),
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
use number_prefix::NumberPrefix;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::blocks::{HumanReadable, SizeFormat};
|
||||
use crate::columns::{Alignment, Column};
|
||||
use crate::filesystem::Filesystem;
|
||||
use crate::{BlockSize, Options};
|
||||
|
@ -213,15 +214,10 @@ impl<'a> RowFormatter<'a> {
|
|||
}
|
||||
|
||||
/// Get a human readable string giving the scaled version of the input number.
|
||||
///
|
||||
/// The scaling factor is defined in the `options` field.
|
||||
///
|
||||
/// This function is supposed to be used by `scaled_bytes()` and `scaled_inodes()` only.
|
||||
fn scaled_human_readable(&self, size: u64) -> String {
|
||||
let number_prefix = match self.options.block_size {
|
||||
BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64),
|
||||
BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64),
|
||||
_ => unreachable!(),
|
||||
fn scaled_human_readable(&self, size: u64, human_readable: HumanReadable) -> String {
|
||||
let number_prefix = match human_readable {
|
||||
HumanReadable::Decimal => NumberPrefix::decimal(size as f64),
|
||||
HumanReadable::Binary => NumberPrefix::binary(size as f64),
|
||||
};
|
||||
match number_prefix {
|
||||
NumberPrefix::Standalone(bytes) => bytes.to_string(),
|
||||
|
@ -233,10 +229,12 @@ impl<'a> RowFormatter<'a> {
|
|||
///
|
||||
/// The scaling factor is defined in the `options` field.
|
||||
fn scaled_bytes(&self, size: u64) -> String {
|
||||
if let BlockSize::Bytes(d) = self.options.block_size {
|
||||
(size / d).to_string()
|
||||
} else {
|
||||
self.scaled_human_readable(size)
|
||||
match self.options.size_format {
|
||||
SizeFormat::HumanReadable(h) => self.scaled_human_readable(size, h),
|
||||
SizeFormat::StaticBlockSize => {
|
||||
let BlockSize::Bytes(d) = self.options.block_size;
|
||||
(size / d).to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,10 +242,9 @@ impl<'a> RowFormatter<'a> {
|
|||
///
|
||||
/// The scaling factor is defined in the `options` field.
|
||||
fn scaled_inodes(&self, size: u64) -> String {
|
||||
if let BlockSize::Bytes(_) = self.options.block_size {
|
||||
size.to_string()
|
||||
} else {
|
||||
self.scaled_human_readable(size)
|
||||
match self.options.size_format {
|
||||
SizeFormat::HumanReadable(h) => self.scaled_human_readable(size, h),
|
||||
SizeFormat::StaticBlockSize => size.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +302,12 @@ impl Header {
|
|||
for column in &options.columns {
|
||||
let header = match column {
|
||||
Column::Source => String::from("Filesystem"),
|
||||
Column::Size => options.block_size.to_string(),
|
||||
Column::Size => match options.size_format {
|
||||
SizeFormat::HumanReadable(_) => String::from("Size"),
|
||||
SizeFormat::StaticBlockSize => {
|
||||
format!("{}-blocks", options.block_size)
|
||||
}
|
||||
},
|
||||
Column::Used => String::from("Used"),
|
||||
Column::Avail => String::from("Available"),
|
||||
Column::Pcent => String::from("Use%"),
|
||||
|
@ -424,6 +426,7 @@ impl fmt::Display for Table {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::blocks::{HumanReadable, SizeFormat};
|
||||
use crate::columns::Column;
|
||||
use crate::table::{Header, Row, RowFormatter};
|
||||
use crate::{BlockSize, Options};
|
||||
|
@ -523,7 +526,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_header_with_human_readable_binary() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableBinary,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Binary),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
|
@ -542,7 +545,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_header_with_human_readable_si() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableDecimal,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Decimal),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
|
@ -689,7 +692,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_formatter_with_human_readable_si() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableDecimal,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Decimal),
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -730,7 +733,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_formatter_with_human_readable_binary() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableBinary,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Binary),
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
..Default::default()
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue