1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

Merge pull request #3430 from cakebaker/human_readable

df: extract HumanReadable from BlockSize
This commit is contained in:
Terts Diepraam 2022-05-05 12:43:59 +02:00 committed by GitHub
commit 6e7abb3320
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 58 deletions

View file

@ -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");
}
}

View file

@ -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),

View file

@ -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()
};