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

refactor: stat declarative macros to functions #3923

Merged
merged 6 commits into from
Sep 17, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 55 additions & 51 deletions src/uu/stat/src/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
extern crate uucore;
use clap::builder::ValueParser;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};
use uucore::error::{FromIo, UError, UResult, USimpleError};
use uucore::fs::display_permissions;
use uucore::fsext::{
pretty_filetype, pretty_fstype, pretty_time, read_fs_list, statfs, BirthTime, FsMeta,
Expand All @@ -26,57 +26,61 @@ use std::os::unix::prelude::OsStrExt;
use std::path::Path;
use std::{cmp, fs, iter};

macro_rules! check_bound {
($str: ident, $bound:expr, $beg: expr, $end: expr) => {
if $end >= $bound {
return Err(USimpleError::new(
1,
format!("{}: invalid directive", $str[$beg..$end].quote()),
));
}
};
fn check_bound(slice: &str, bound: usize, beg: usize, end: usize) -> Result<(), Box<dyn UError>> {
snapdgn marked this conversation as resolved.
Show resolved Hide resolved
if end >= bound {
return Err(USimpleError::new(
1,
format!("{}: invalid directive", slice[beg..end].quote()),
));
}
Ok(())
}
macro_rules! fill_string {
($str: ident, $c: expr, $cnt: expr) => {
iter::repeat($c)
.take($cnt)
.map(|c| $str.push(c))
.all(|_| true)
};

fn fill_string(strs: &mut String, c: char, cnt: usize) {
iter::repeat(c)
.take(cnt)
.map(|c| strs.push(c))
.all(|_| true);
}
macro_rules! extend_digits {
($str: expr, $min: expr) => {
if $min > $str.len() {
let mut pad = String::with_capacity($min);
fill_string!(pad, '0', $min - $str.len());
pad.push_str($str);
pad.into()
} else {
$str.into()
}
};

fn extend_digits(strs: &str, min: usize) -> Cow<'_, str> {
if min > strs.len() {
let mut pad = String::with_capacity(min);
fill_string(&mut pad, '0', min - strs.len());
pad.push_str(strs);
return pad.into();
} else {
return strs.into();
}
}
macro_rules! pad_and_print {
($result: ident, $str: ident, $left: expr, $width: expr, $padding: expr) => {
if $str.len() < $width {
if $left {
$result.push_str($str.as_ref());
fill_string!($result, $padding, $width - $str.len());
} else {
fill_string!($result, $padding, $width - $str.len());
$result.push_str($str.as_ref());
}

fn pad_and_print<S: AsRef<str>>(
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be simplified by using format specifiers in the print! call. The only problem is that we have to make it slightly less general and only support '0' and ' ' as padding characters, because the format specification does not support general fill characters. It would look something like:

enum Padding {
    Zero,
    Space,
}

fn pad_and_print(result: &str, left: bool, width: usize, padding: Padding) {
    match (left, padding) {
        (false, Padding::Zero) => print!("{result:0>width$}"),
        (false, Padding::Space) => print!("{result:>width$}"),
        (true, Padding::Zero) => print!("{result:0<width$}"),
        (true, Padding::Space) => print!("{result:<width$}"),
    };
}

I think that with this implementation we can get rid of fill_string altogether.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for the input, I've updated the changes. Please take a look at it at your convenience. Thanks :)

result: &mut String,
strs: S,
left: bool,
width: usize,
padding: char,
) {
let strs_ref = strs.as_ref();
if strs_ref.len() < width {
if left {
result.push_str(strs.as_ref());
fill_string(result, padding, width - strs_ref.len());
} else {
$result.push_str($str.as_ref());
fill_string(result, padding, width - strs_ref.len());
result.push_str(strs.as_ref());
}
print!("{}", $result);
};
} else {
result.push_str(strs.as_ref());
}
print!("{}", result);
}

macro_rules! print_adjusted {
($str: ident, $left: expr, $width: expr, $padding: expr) => {
let field_width = cmp::max($width, $str.len());
let mut result = String::with_capacity(field_width);
pad_and_print!(result, $str, $left, field_width, $padding);
pad_and_print(&mut result, $str, $left, field_width, $padding);
};
($str: ident, $left: expr, $need_prefix: expr, $prefix: expr, $width: expr, $padding: expr) => {
let mut field_width = cmp::max($width, $str.len());
Expand All @@ -85,7 +89,7 @@ macro_rules! print_adjusted {
result.push_str($prefix);
field_width -= $prefix.len();
}
pad_and_print!(result, $str, $left, field_width, $padding);
pad_and_print(&mut result, $str, $left, field_width, $padding);
};
}

Expand Down Expand Up @@ -306,7 +310,7 @@ fn print_it(arg: &str, output_type: &OutputType, flag: u8, width: usize, precisi
Cow::Borrowed(arg)
};
let min_digits = cmp::max(precision, arg.len() as i32) as usize;
let extended: Cow<str> = extend_digits!(arg.as_ref(), min_digits);
let extended: Cow<str> = extend_digits(arg.as_ref(), min_digits);
print_adjusted!(extended, left_align, has_sign, prefix, width, padding_char);
}
OutputType::Unsigned => {
Expand All @@ -316,12 +320,12 @@ fn print_it(arg: &str, output_type: &OutputType, flag: u8, width: usize, precisi
Cow::Borrowed(arg)
};
let min_digits = cmp::max(precision, arg.len() as i32) as usize;
let extended: Cow<str> = extend_digits!(arg.as_ref(), min_digits);
let extended: Cow<str> = extend_digits(arg.as_ref(), min_digits);
print_adjusted!(extended, left_align, width, padding_char);
}
OutputType::UnsignedOct => {
let min_digits = cmp::max(precision, arg.len() as i32) as usize;
let extended: Cow<str> = extend_digits!(arg, min_digits);
let extended: Cow<str> = extend_digits(arg, min_digits);
print_adjusted!(
extended,
left_align,
Expand All @@ -333,7 +337,7 @@ fn print_it(arg: &str, output_type: &OutputType, flag: u8, width: usize, precisi
}
OutputType::UnsignedHex => {
let min_digits = cmp::max(precision, arg.len() as i32) as usize;
let extended: Cow<str> = extend_digits!(arg, min_digits);
let extended: Cow<str> = extend_digits(arg, min_digits);
print_adjusted!(
extended,
left_align,
Expand Down Expand Up @@ -384,7 +388,7 @@ impl Stater {
}
i += 1;
}
check_bound!(format_str, bound, old, i);
check_bound(format_str, bound, old, i)?;

let mut width = 0_usize;
let mut precision = -1_i32;
Expand All @@ -394,11 +398,11 @@ impl Stater {
width = field_width;
j += offset;
}
check_bound!(format_str, bound, old, j);
check_bound(format_str, bound, old, j)?;

if chars[j] == '.' {
j += 1;
check_bound!(format_str, bound, old, j);
check_bound(format_str, bound, old, j)?;

match format_str[j..].scan_num::<i32>() {
Some((value, offset)) => {
Expand All @@ -409,7 +413,7 @@ impl Stater {
}
None => precision = 0,
}
check_bound!(format_str, bound, old, j);
check_bound(format_str, bound, old, j)?;
}

i = j;
Expand Down