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;
|
||||
#[cfg(feature = "compression")]
|
||||
fn UTIL_countLogicalCores() -> c_int;
|
||||
fn UTIL_getFileSize(input_file_name: *const c_char) -> u64;
|
||||
fn UTIL_createFileNamesTable_fromFileName(
|
||||
input_file_name: *const c_char,
|
||||
) -> *mut FileNamesTable;
|
||||
@@ -226,8 +227,27 @@ unsafe extern "C" {
|
||||
block_size: usize,
|
||||
nb_workers: 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)]
|
||||
enum Operation {
|
||||
Compress,
|
||||
@@ -285,6 +305,7 @@ struct Cli {
|
||||
row_match_finder: i32,
|
||||
exclude_compressed: bool,
|
||||
compression_params: ZSTD_compressionParameters,
|
||||
show_default_cparams: bool,
|
||||
bench_end_level: Option<i32>,
|
||||
bench_nb_seconds: Option<u32>,
|
||||
recursive: bool,
|
||||
@@ -336,6 +357,7 @@ impl Cli {
|
||||
row_match_finder: ZSTD_PS_AUTO,
|
||||
exclude_compressed: false,
|
||||
compression_params: ZSTD_compressionParameters::default(),
|
||||
show_default_cparams: false,
|
||||
bench_end_level: None,
|
||||
bench_nb_seconds: None,
|
||||
recursive: false,
|
||||
@@ -784,6 +806,7 @@ fn parse_long_option(
|
||||
| "--exclude-compressed"
|
||||
| "--no-name"
|
||||
| "--list"
|
||||
| "--show-default-cparams"
|
||||
)
|
||||
{
|
||||
return Err(format!("{name} does not take an argument"));
|
||||
@@ -993,6 +1016,10 @@ fn parse_long_option(
|
||||
cli.operation = Operation::List;
|
||||
Ok(None)
|
||||
}
|
||||
"--show-default-cparams" => {
|
||||
cli.show_default_cparams = true;
|
||||
Ok(None)
|
||||
}
|
||||
"--filelist" => {
|
||||
let value = next_field(attached, args, index, name)?;
|
||||
cli.file_lists.push(cstring(&value)?);
|
||||
@@ -1038,8 +1065,7 @@ fn parse_long_option(
|
||||
| "--fake-stdin-is-console"
|
||||
| "--fake-stdout-is-console"
|
||||
| "--fake-stderr-is-console"
|
||||
| "--trace-file-stat"
|
||||
| "--show-default-cparams" => {
|
||||
| "--trace-file-stat" => {
|
||||
unsupported(name)?;
|
||||
Ok(None)
|
||||
}
|
||||
@@ -1353,6 +1379,76 @@ fn check_terminal_safety(cli: &Cli) -> Result<(), String> {
|
||||
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")]
|
||||
unsafe fn run_compress(
|
||||
cli: &Cli,
|
||||
@@ -1593,6 +1689,10 @@ fn run_cli(mut cli: Cli) -> Result<i32, String> {
|
||||
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)?;
|
||||
|
||||
if cli.operation == Operation::Compress {
|
||||
@@ -1648,6 +1748,15 @@ fn run_cli(mut cli: Cli) -> Result<i32, String> {
|
||||
unsafe {
|
||||
FIO_addAbortHandler();
|
||||
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
|
||||
.output
|
||||
@@ -1949,6 +2058,25 @@ mod tests {
|
||||
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]
|
||||
fn filelist_accumulates_both_syntaxes() {
|
||||
let cli = parse(&["zstd", "--filelist=one.txt", "--filelist", "two.txt", "in"]);
|
||||
|
||||
Reference in New Issue
Block a user