feat(cli): port default compression parameter reporting
Implement the Rust frontend's --show-default-cparams path, including source and dictionary size discovery, strategy labels, verbose --zstd parameter reporting, and the decompression-mode diagnostic. Keep the C parameter API as the source of the selected values so the CLI remains aligned with the active compression build. Test Plan: - cargo test --manifest-path rust/cli/Cargo.toml - cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - rustfmt +nightly --edition 2021 rust/src/zstd_cli.rs - git diff --check Depends-on: Rust CLI parser, file-selection, and C fileio bridge ports
This commit is contained in:
+130
-2
@@ -105,6 +105,7 @@ unsafe extern "C" {
|
|||||||
fn UTIL_countPhysicalCores() -> c_int;
|
fn UTIL_countPhysicalCores() -> c_int;
|
||||||
#[cfg(feature = "compression")]
|
#[cfg(feature = "compression")]
|
||||||
fn UTIL_countLogicalCores() -> c_int;
|
fn UTIL_countLogicalCores() -> c_int;
|
||||||
|
fn UTIL_getFileSize(input_file_name: *const c_char) -> u64;
|
||||||
fn UTIL_createFileNamesTable_fromFileName(
|
fn UTIL_createFileNamesTable_fromFileName(
|
||||||
input_file_name: *const c_char,
|
input_file_name: *const c_char,
|
||||||
) -> *mut FileNamesTable;
|
) -> *mut FileNamesTable;
|
||||||
@@ -226,8 +227,27 @@ unsafe extern "C" {
|
|||||||
block_size: usize,
|
block_size: usize,
|
||||||
nb_workers: c_int,
|
nb_workers: c_int,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
#[cfg(feature = "compression")]
|
||||||
|
fn ZSTD_getCParams(
|
||||||
|
compression_level: c_int,
|
||||||
|
estimated_src_size: u64,
|
||||||
|
dict_size: usize,
|
||||||
|
) -> ZSTD_compressionParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ZSTD_STRATEGY_NAMES: [&str; 10] = [
|
||||||
|
"",
|
||||||
|
"ZSTD_fast",
|
||||||
|
"ZSTD_dfast",
|
||||||
|
"ZSTD_greedy",
|
||||||
|
"ZSTD_lazy",
|
||||||
|
"ZSTD_lazy2",
|
||||||
|
"ZSTD_btlazy2",
|
||||||
|
"ZSTD_btopt",
|
||||||
|
"ZSTD_btultra",
|
||||||
|
"ZSTD_btultra2",
|
||||||
|
];
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum Operation {
|
enum Operation {
|
||||||
Compress,
|
Compress,
|
||||||
@@ -285,6 +305,7 @@ struct Cli {
|
|||||||
row_match_finder: i32,
|
row_match_finder: i32,
|
||||||
exclude_compressed: bool,
|
exclude_compressed: bool,
|
||||||
compression_params: ZSTD_compressionParameters,
|
compression_params: ZSTD_compressionParameters,
|
||||||
|
show_default_cparams: bool,
|
||||||
bench_end_level: Option<i32>,
|
bench_end_level: Option<i32>,
|
||||||
bench_nb_seconds: Option<u32>,
|
bench_nb_seconds: Option<u32>,
|
||||||
recursive: bool,
|
recursive: bool,
|
||||||
@@ -336,6 +357,7 @@ impl Cli {
|
|||||||
row_match_finder: ZSTD_PS_AUTO,
|
row_match_finder: ZSTD_PS_AUTO,
|
||||||
exclude_compressed: false,
|
exclude_compressed: false,
|
||||||
compression_params: ZSTD_compressionParameters::default(),
|
compression_params: ZSTD_compressionParameters::default(),
|
||||||
|
show_default_cparams: false,
|
||||||
bench_end_level: None,
|
bench_end_level: None,
|
||||||
bench_nb_seconds: None,
|
bench_nb_seconds: None,
|
||||||
recursive: false,
|
recursive: false,
|
||||||
@@ -784,6 +806,7 @@ fn parse_long_option(
|
|||||||
| "--exclude-compressed"
|
| "--exclude-compressed"
|
||||||
| "--no-name"
|
| "--no-name"
|
||||||
| "--list"
|
| "--list"
|
||||||
|
| "--show-default-cparams"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return Err(format!("{name} does not take an argument"));
|
return Err(format!("{name} does not take an argument"));
|
||||||
@@ -993,6 +1016,10 @@ fn parse_long_option(
|
|||||||
cli.operation = Operation::List;
|
cli.operation = Operation::List;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
"--show-default-cparams" => {
|
||||||
|
cli.show_default_cparams = true;
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
"--filelist" => {
|
"--filelist" => {
|
||||||
let value = next_field(attached, args, index, name)?;
|
let value = next_field(attached, args, index, name)?;
|
||||||
cli.file_lists.push(cstring(&value)?);
|
cli.file_lists.push(cstring(&value)?);
|
||||||
@@ -1038,8 +1065,7 @@ fn parse_long_option(
|
|||||||
| "--fake-stdin-is-console"
|
| "--fake-stdin-is-console"
|
||||||
| "--fake-stdout-is-console"
|
| "--fake-stdout-is-console"
|
||||||
| "--fake-stderr-is-console"
|
| "--fake-stderr-is-console"
|
||||||
| "--trace-file-stat"
|
| "--trace-file-stat" => {
|
||||||
| "--show-default-cparams" => {
|
|
||||||
unsupported(name)?;
|
unsupported(name)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@@ -1353,6 +1379,76 @@ fn check_terminal_safety(cli: &Cli) -> Result<(), String> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compression")]
|
||||||
|
unsafe fn print_default_cparams(cli: &Cli) {
|
||||||
|
let dict_size = cli.dictionary.as_ref().map_or(0, |dictionary| unsafe {
|
||||||
|
UTIL_getFileSize(dictionary.as_ptr()) as usize
|
||||||
|
});
|
||||||
|
for input in &cli.inputs {
|
||||||
|
let file_size = unsafe { UTIL_getFileSize(input.as_ptr()) };
|
||||||
|
let cparams = unsafe { ZSTD_getCParams(cli.level, file_size, dict_size) };
|
||||||
|
let strategy = ZSTD_STRATEGY_NAMES
|
||||||
|
.get(cparams.strategy as usize)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or("");
|
||||||
|
if file_size != u64::MAX {
|
||||||
|
eprintln!("{} ({} bytes)", input.to_string_lossy(), file_size);
|
||||||
|
} else {
|
||||||
|
eprintln!("{} (src size unknown)", input.to_string_lossy());
|
||||||
|
}
|
||||||
|
eprintln!(" - windowLog : {}", cparams.windowLog);
|
||||||
|
eprintln!(" - chainLog : {}", cparams.chainLog);
|
||||||
|
eprintln!(" - hashLog : {}", cparams.hashLog);
|
||||||
|
eprintln!(" - searchLog : {}", cparams.searchLog);
|
||||||
|
eprintln!(" - minMatch : {}", cparams.minMatch);
|
||||||
|
eprintln!(" - targetLength : {}", cparams.targetLength);
|
||||||
|
eprintln!(" - strategy : {strategy} ({})", cparams.strategy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compression")]
|
||||||
|
unsafe fn print_actual_cparams(cli: &Cli) {
|
||||||
|
let dict_size = cli.dictionary.as_ref().map_or(0, |dictionary| unsafe {
|
||||||
|
UTIL_getFileSize(dictionary.as_ptr()) as usize
|
||||||
|
});
|
||||||
|
for input in &cli.inputs {
|
||||||
|
let file_size = unsafe { UTIL_getFileSize(input.as_ptr()) };
|
||||||
|
let mut actual = unsafe { ZSTD_getCParams(cli.level, file_size, dict_size) };
|
||||||
|
let requested = cli.compression_params;
|
||||||
|
if requested.windowLog != 0 {
|
||||||
|
actual.windowLog = requested.windowLog;
|
||||||
|
}
|
||||||
|
if requested.chainLog != 0 {
|
||||||
|
actual.chainLog = requested.chainLog;
|
||||||
|
}
|
||||||
|
if requested.hashLog != 0 {
|
||||||
|
actual.hashLog = requested.hashLog;
|
||||||
|
}
|
||||||
|
if requested.searchLog != 0 {
|
||||||
|
actual.searchLog = requested.searchLog;
|
||||||
|
}
|
||||||
|
if requested.minMatch != 0 {
|
||||||
|
actual.minMatch = requested.minMatch;
|
||||||
|
}
|
||||||
|
if requested.targetLength != 0 {
|
||||||
|
actual.targetLength = requested.targetLength;
|
||||||
|
}
|
||||||
|
if requested.strategy != 0 {
|
||||||
|
actual.strategy = requested.strategy;
|
||||||
|
}
|
||||||
|
eprintln!(
|
||||||
|
"--zstd=wlog={},clog={},hlog={},slog={},mml={},tlen={},strat={}",
|
||||||
|
actual.windowLog,
|
||||||
|
actual.chainLog,
|
||||||
|
actual.hashLog,
|
||||||
|
actual.searchLog,
|
||||||
|
actual.minMatch,
|
||||||
|
actual.targetLength,
|
||||||
|
actual.strategy
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compression")]
|
#[cfg(feature = "compression")]
|
||||||
unsafe fn run_compress(
|
unsafe fn run_compress(
|
||||||
cli: &Cli,
|
cli: &Cli,
|
||||||
@@ -1593,6 +1689,10 @@ fn run_cli(mut cli: Cli) -> Result<i32, String> {
|
|||||||
cli.output = Some(cstring(STDOUT_MARK)?);
|
cli.output = Some(cstring(STDOUT_MARK)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cli.show_default_cparams && cli.operation == Operation::Decompress {
|
||||||
|
return Err("error : can't use --show-default-cparams in decompression mode".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
check_terminal_safety(&cli)?;
|
check_terminal_safety(&cli)?;
|
||||||
|
|
||||||
if cli.operation == Operation::Compress {
|
if cli.operation == Operation::Compress {
|
||||||
@@ -1648,6 +1748,15 @@ fn run_cli(mut cli: Cli) -> Result<i32, String> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
FIO_addAbortHandler();
|
FIO_addAbortHandler();
|
||||||
apply_preferences(&cli, prefs, ctx);
|
apply_preferences(&cli, prefs, ctx);
|
||||||
|
#[cfg(feature = "compression")]
|
||||||
|
if cli.operation == Operation::Compress {
|
||||||
|
if cli.show_default_cparams {
|
||||||
|
print_default_cparams(&cli);
|
||||||
|
}
|
||||||
|
if cli.display_level >= 4 {
|
||||||
|
print_actual_cparams(&cli);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let output = cli
|
let output = cli
|
||||||
.output
|
.output
|
||||||
@@ -1949,6 +2058,25 @@ mod tests {
|
|||||||
assert!(error.contains("does not take an argument"));
|
assert!(error.contains("does not take an argument"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn show_default_cparams_is_a_compression_information_flag() {
|
||||||
|
let cli = parse(&["zstd", "--show-default-cparams", "input"]);
|
||||||
|
|
||||||
|
assert!(cli.show_default_cparams);
|
||||||
|
assert_eq!(cli.operation, Operation::Compress);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn show_default_cparams_rejects_attached_values() {
|
||||||
|
let error = parse_args(vec![
|
||||||
|
OsString::from("zstd"),
|
||||||
|
OsString::from("--show-default-cparams=x"),
|
||||||
|
])
|
||||||
|
.expect_err("show-default-cparams must not consume an attached value");
|
||||||
|
|
||||||
|
assert!(error.contains("does not take an argument"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn filelist_accumulates_both_syntaxes() {
|
fn filelist_accumulates_both_syntaxes() {
|
||||||
let cli = parse(&["zstd", "--filelist=one.txt", "--filelist", "two.txt", "in"]);
|
let cli = parse(&["zstd", "--filelist=one.txt", "--filelist", "two.txt", "in"]);
|
||||||
|
|||||||
Reference in New Issue
Block a user