diff --git a/Cargo.toml b/Cargo.toml index b3ebd336e..1dc20b4b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -748,7 +748,6 @@ ignored_unit_patterns = "allow" # 21 similar_names = "allow" # 20 needless_pass_by_value = "allow" # 16 float_cmp = "allow" # 12 -items_after_statements = "allow" # 11 return_self_not_must_use = "allow" # 8 inline_always = "allow" # 6 fn_params_excessive_bools = "allow" # 6 diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs index 1ef6c4193..69ab04108 100644 --- a/src/bin/uudoc.rs +++ b/src/bin/uudoc.rs @@ -16,8 +16,13 @@ use std::{ use clap::{Arg, Command}; use clap_complete::Shell; use clap_mangen::Man; -use fluent_syntax::ast::{Entry, Message, Pattern}; -use fluent_syntax::parser; +use fluent_syntax::{ + ast::{ + Entry, Expression, InlineExpression, Message, Pattern, + PatternElement::{Placeable, TextElement}, + }, + parser, +}; use jiff::Zoned; use regex::Regex; use textwrap::{fill, indent, termwidth}; @@ -447,10 +452,6 @@ impl MDWriter<'_, '_> { if id.name == key { // Simple text extraction - just concatenate text elements let mut result = String::new(); - use fluent_syntax::ast::{ - Expression, InlineExpression, - PatternElement::{Placeable, TextElement}, - }; for element in elements { if let TextElement { ref value } = element { result.push_str(value); diff --git a/src/uu/chcon/src/chcon.rs b/src/uu/chcon/src/chcon.rs index c1e66d44c..de4696913 100644 --- a/src/uu/chcon/src/chcon.rs +++ b/src/uu/chcon/src/chcon.rs @@ -627,6 +627,8 @@ fn change_file_context( context: &SELinuxSecurityContext, path: &Path, ) -> Result<()> { + type SetValueProc = fn(&OpaqueSecurityContext, &CStr) -> selinux::errors::Result<()>; + match &options.mode { CommandLineMode::Custom { user, @@ -673,8 +675,6 @@ fn change_file_context( Error::from_io1(translate!("chcon-op-creating-security-context"), path, err) })?; - type SetValueProc = fn(&OpaqueSecurityContext, &CStr) -> selinux::errors::Result<()>; - let list: &[(&Option, SetValueProc)] = &[ (user, OpaqueSecurityContext::set_user), (role, OpaqueSecurityContext::set_role), diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index df3f46a14..b097be2c9 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -22,8 +22,6 @@ use uucore::translate; /// 2>/dev/full does not abort /// This matches GNU cksum's --debug behavior fn print_cpu_debug_info() { - let features = SimdPolicy::detect(); - fn print_feature(name: &str, available: bool) { if available { let _ = writeln!(stderr(), "using {name} hardware support"); @@ -32,6 +30,8 @@ fn print_cpu_debug_info() { } } + let features = SimdPolicy::detect(); + // x86/x86_64 print_feature("avx512", features.has_avx512()); print_feature("avx2", features.has_avx2()); diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 2e9ae6b62..c48cfda52 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -2384,8 +2384,7 @@ fn calculate_dest_permissions( let mode = handle_no_preserve_mode(options, permissions.mode()); // Apply umask - use uucore::mode::get_umask; - let mode = mode & !get_umask(); + let mode = mode & !uucore::mode::get_umask(); permissions.set_mode(mode); permissions } diff --git a/src/uu/df/src/table.rs b/src/uu/df/src/table.rs index d4cf1ddfd..1e5016a70 100644 --- a/src/uu/df/src/table.rs +++ b/src/uu/df/src/table.rs @@ -950,7 +950,6 @@ mod tests { #[test] fn test_row_formatter_with_round_up_byte_values() { - init(); fn get_formatted_values(bytes: u64, bytes_used: u64, bytes_avail: u64) -> Vec { let options = Options { block_size: BlockSize::Bytes(1000), @@ -967,6 +966,8 @@ mod tests { RowFormatter::new(&row, &options, false).get_cells() } + init(); + assert!(compare_cell_content( get_formatted_values(100, 100, 0), vec!("1", "1", "0") diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index cf4ae5420..fa91da7ac 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -426,6 +426,10 @@ fn safe_du( }; 'file_loop: for entry_name in entries { + const S_IFMT: u32 = 0o170_000; + const S_IFDIR: u32 = 0o040_000; + const S_IFLNK: u32 = 0o120_000; + // First get the lstat (without following symlinks) to check if it's a symlink let lstat = match dir_fd.stat_at(&entry_name, SymlinkBehavior::NoFollow) { Ok(stat) => stat, @@ -439,9 +443,6 @@ fn safe_du( }; // Check if it's a symlink - const S_IFMT: u32 = 0o170_000; - const S_IFDIR: u32 = 0o040_000; - const S_IFLNK: u32 = 0o120_000; #[allow(clippy::unnecessary_cast)] let is_symlink = (lstat.st_mode as u32 & S_IFMT) == S_IFLNK; @@ -575,11 +576,12 @@ fn du_regular( ancestors: Option<&mut HashSet>, symlink_depth: Option, ) -> Result>>> { + // Maximum symlink depth to prevent infinite loops + const MAX_SYMLINK_DEPTH: usize = 40; + let mut default_ancestors = HashSet::default(); let ancestors = ancestors.unwrap_or(&mut default_ancestors); let symlink_depth = symlink_depth.unwrap_or(0); - // Maximum symlink depth to prevent infinite loops - const MAX_SYMLINK_DEPTH: usize = 40; // Add current directory to ancestors if it's a directory let my_inode = if my_stat.metadata.is_dir() { diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index 2c2599a84..a7f93096b 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -268,9 +268,9 @@ fn check_posix_regex_errors(pattern: &str) -> ExprResult<()> { /// Build a regex from a pattern string with locale-aware encoding fn build_regex(pattern_bytes: Vec) -> ExprResult<(Regex, String)> { use onig::EncodedBytes; - use uucore::i18n::{UEncoding, get_locale_encoding}; + use uucore::i18n::UEncoding; - let encoding = get_locale_encoding(); + let encoding = uucore::i18n::get_locale_encoding(); // For pattern processing, we need to handle it based on locale let pattern_str = String::from_utf8(pattern_bytes.clone()) @@ -388,9 +388,9 @@ fn regex_search( /// Find matches in the input using the compiled regex fn find_match(regex: Regex, re_string: String, left_bytes: Vec) -> String { use onig::EncodedBytes; - use uucore::i18n::{UEncoding, get_locale_encoding}; + use uucore::i18n::UEncoding; - let encoding = get_locale_encoding(); + let encoding = uucore::i18n::get_locale_encoding(); // Match against the input using the appropriate encoding let mut region = onig::Region::new(); @@ -506,11 +506,12 @@ fn find_match(regex: Regex, re_string: String, left_bytes: Vec) -> String { /// Evaluate a match expression with locale-aware regex matching fn evaluate_match_expression(left_bytes: Vec, right_bytes: Vec) -> ExprResult { + use uucore::i18n::UEncoding; + let (regex, re_string) = build_regex(right_bytes)?; // Special case for ASCII locale with capture groups that need to return raw bytes - use uucore::i18n::{UEncoding, get_locale_encoding}; - let encoding = get_locale_encoding(); + let encoding = uucore::i18n::get_locale_encoding(); if matches!(encoding, UEncoding::Ascii) && regex.captures_len() > 0 { // Try to find the actual capture bytes for ASCII locale diff --git a/src/uu/mknod/src/mknod.rs b/src/uu/mknod/src/mknod.rs index 39ac62cb6..e8272f6ab 100644 --- a/src/uu/mknod/src/mknod.rs +++ b/src/uu/mknod/src/mknod.rs @@ -98,14 +98,15 @@ fn mknod(file_name: &str, config: Config) -> i32 { // Apply SELinux context if requested #[cfg(feature = "selinux")] if config.set_security_context { + use std::io::Write as _; + if let Err(e) = uucore::selinux::set_selinux_security_context( std::path::Path::new(file_name), config.context.as_ref(), ) { // if it fails, delete the file let _ = std::fs::remove_file(file_name); - use std::io::{Write, stderr}; - let _ = writeln!(stderr(), "mknod: {e}"); + let _ = writeln!(std::io::stderr(), "mknod: {e}"); return 1; } } @@ -113,13 +114,14 @@ fn mknod(file_name: &str, config: Config) -> i32 { // Apply SMACK context if requested #[cfg(feature = "smack")] if config.set_security_context { + use std::io::Write as _; + if let Err(e) = uucore::smack::set_smack_label_and_cleanup(file_name, config.context.as_ref(), |p| { std::fs::remove_file(p) }) { - use std::io::{Write, stderr}; - let _ = writeln!(stderr(), "mknod: {e}"); + let _ = writeln!(std::io::stderr(), "mknod: {e}"); return 1; } } diff --git a/src/uu/sort/src/chunks.rs b/src/uu/sort/src/chunks.rs index ce6b2118b..62fb9fe4e 100644 --- a/src/uu/sort/src/chunks.rs +++ b/src/uu/sort/src/chunks.rs @@ -269,6 +269,8 @@ fn parse_lines<'a>( separator: u8, settings: &GlobalSettings, ) { + const SMALL_CHUNK_BYTES: usize = 64 * 1024; + let read = read.strip_suffix(&[separator]).unwrap_or(read); assert!(lines.is_empty()); @@ -279,7 +281,6 @@ fn parse_lines<'a>( assert!(line_data.collation_key_buffer.is_empty()); assert!(line_data.collation_key_ends.is_empty()); token_buffer.clear(); - const SMALL_CHUNK_BYTES: usize = 64 * 1024; let mut estimated = (*line_count_hint).max(1); let mut exact_line_count = None; if *line_count_hint == 0 || read.len() <= SMALL_CHUNK_BYTES { diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 8b321b55d..32a919a32 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -2834,11 +2834,12 @@ fn ascii_case_insensitive_cmp(a: &[u8], b: &[u8]) -> Ordering { // For example, 5e10KFD would be 5e10 or 5x10^10 and +10000HFKJFK would become 10000. #[allow(clippy::cognitive_complexity)] fn get_leading_gen(inp: &[u8], decimal_pt: u8) -> Range { + // check for inf, -inf and nan + const ALLOWED_PREFIXES: &[&[u8]] = &[b"inf", b"-inf", b"nan"]; + let trimmed = inp.trim_ascii_start(); let leading_whitespace_len = inp.len() - trimmed.len(); - // check for inf, -inf and nan - const ALLOWED_PREFIXES: &[&[u8]] = &[b"inf", b"-inf", b"nan"]; for &allowed_prefix in ALLOWED_PREFIXES { if trimmed.len() >= allowed_prefix.len() && trimmed[..allowed_prefix.len()].eq_ignore_ascii_case(allowed_prefix) diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 0bf64922b..a5128bf68 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -145,12 +145,12 @@ fn get_preload_env(tmp_dir: &TempDir) -> UResult<(String, PathBuf)> { #[cfg(feature = "feat_external_libstdbuf")] fn get_preload_env(_tmp_dir: &TempDir) -> UResult<(String, PathBuf)> { - let (preload, extension) = preload_strings(); - // Use the directory provided at compile time via LIBSTDBUF_DIR environment variable // This will fail to compile if LIBSTDBUF_DIR is not set, which is the desired behavior const LIBSTDBUF_DIR: &str = env!("LIBSTDBUF_DIR"); + let (preload, extension) = preload_strings(); + // Search paths in order: // 1. Directory where stdbuf is located (program_path) // 2. Compile-time directory from LIBSTDBUF_DIR diff --git a/src/uu/wc/src/utf8/read.rs b/src/uu/wc/src/utf8/read.rs index 6364c45df..dabf1a380 100644 --- a/src/uu/wc/src/utf8/read.rs +++ b/src/uu/wc/src/utf8/read.rs @@ -67,8 +67,7 @@ impl BufReadDecoder { let buf = try_io!(self.buf_read.fill_buf()); // Force loop iteration to go through an explicit `continue` - enum Unreachable {} - let _: Unreachable = if self.incomplete.is_empty() { + let _: std::convert::Infallible = if self.incomplete.is_empty() { if buf.is_empty() { return None; // EOF } diff --git a/src/uucore/src/lib/features/checksum/validate.rs b/src/uucore/src/lib/features/checksum/validate.rs index bd2993e82..df58c1f35 100644 --- a/src/uucore/src/lib/features/checksum/validate.rs +++ b/src/uucore/src/lib/features/checksum/validate.rs @@ -267,16 +267,17 @@ impl LineFormat { /// /// [tagged output format]: https://www.gnu.org/software/coreutils/manual/html_node/cksum-output-modes.html#cksum-output-modes-1 fn parse_algo_based(line: &[u8]) -> Option { + enum SubCase { + Posix, + OpenSSL, + } + // r"\MD5 (a\\ b) = abc123", // BLAKE2b(44)= a45a4c4883cce4b50d844fab460414cc2080ca83690e74d850a9253e757384366382625b218c8585daee80f34dc9eb2f2fde5fb959db81cd48837f9216e7b0fa let trimmed = line.trim_ascii_start(); let algo_start = usize::from(trimmed.starts_with(b"\\")); let rest = &trimmed[algo_start..]; - enum SubCase { - Posix, - OpenSSL, - } // find the next parenthesis using byte search (not next whitespace) because openssl's // tagged format does not put a space before (filename) @@ -858,6 +859,8 @@ fn process_checksum_file( cli_algo_length: Option, opts: ChecksumValidateOptions, ) -> Result<(), FileCheckError> { + use LineCheckError::*; + let mut res = ChecksumResult::default(); let input_is_stdin = filename_input == OsStr::new("-"); @@ -906,7 +909,6 @@ fn process_checksum_file( // Match a first time to elude critical UErrors, and increment the total // in all cases except on skipped. - use LineCheckError::*; match line_result { Err(UError(e)) => return Err(e.into()), Err(Skipped) => (), diff --git a/src/uucore/src/lib/features/encoding.rs b/src/uucore/src/lib/features/encoding.rs index d782b6896..db6114d27 100644 --- a/src/uucore/src/lib/features/encoding.rs +++ b/src/uucore/src/lib/features/encoding.rs @@ -567,12 +567,12 @@ impl SupportsFastDecodeAndEncode for Base32Wrapper { } fn pad_remainder(&self, remainder: &[u8]) -> Option { + const VALID_REMAINDERS: [usize; 4] = [2, 4, 5, 7]; + if remainder.is_empty() || remainder.contains(&b'=') { return None; } - const VALID_REMAINDERS: [usize; 4] = [2, 4, 5, 7]; - let mut len = remainder.len(); let mut trimmed = false; diff --git a/src/uucore/src/lib/features/format/num_format.rs b/src/uucore/src/lib/features/format/num_format.rs index 9d44491b4..699cdf0da 100644 --- a/src/uucore/src/lib/features/format/num_format.rs +++ b/src/uucore/src/lib/features/format/num_format.rs @@ -534,6 +534,9 @@ fn format_float_hexadecimal( case: Case, force_decimal: ForceDecimal, ) -> String { + // TODO: Make this configurable? e.g. arm64 only displays 1 digit. + const BEFORE_BITS: usize = 4; + debug_assert!(!bd.is_negative()); // Default precision for %a is supposed to be sufficient to represent the // exact value. This is platform specific, GNU coreutils uses a `long double`, @@ -611,8 +614,6 @@ fn format_float_hexadecimal( // Emulate x86(-64) behavior, we display 4 binary digits before the decimal point, // so the value will always be between 0x8 and 0xf. - // TODO: Make this configurable? e.g. arm64 only displays 1 digit. - const BEFORE_BITS: usize = 4; let wanted_bits = (BEFORE_BITS + max_precision * 4) as u64; let bits = frac2.bits(); diff --git a/src/uucore/src/lib/features/parser/num_parser.rs b/src/uucore/src/lib/features/parser/num_parser.rs index 7550e8dd7..6d6fb5ebc 100644 --- a/src/uucore/src/lib/features/parser/num_parser.rs +++ b/src/uucore/src/lib/features/parser/num_parser.rs @@ -348,8 +348,6 @@ fn parse_special_value( negative: bool, allowed_suffixes: &[(char, u32)], ) -> Result> { - let input_lc = input.to_ascii_lowercase(); - // Array of ("String to match", return value when sign positive, when sign negative) const MATCH_TABLE: &[(&str, ExtendedBigDecimal)] = &[ ("infinity", ExtendedBigDecimal::Infinity), @@ -357,6 +355,8 @@ fn parse_special_value( ("nan", ExtendedBigDecimal::Nan), ]; + let input_lc = input.to_ascii_lowercase(); + for (str, ebd) in MATCH_TABLE { if input_lc.starts_with(str) { let mut special = ebd.clone(); diff --git a/src/uucore/src/lib/features/parser/parse_time.rs b/src/uucore/src/lib/features/parser/parse_time.rs index 5435bd823..3c4c155d2 100644 --- a/src/uucore/src/lib/features/parser/parse_time.rs +++ b/src/uucore/src/lib/features/parser/parse_time.rs @@ -54,6 +54,8 @@ use std::time::Duration; /// assert!(from_str("2d", false).is_err()); /// ``` pub fn from_str(string: &str, allow_suffixes: bool) -> Result { + const NANOS_PER_SEC: u32 = 1_000_000_000; + // TODO: Switch to Duration::NANOSECOND if that ever becomes stable // https://github.com/rust-lang/rust/issues/57391 const NANOSECOND_DURATION: Duration = Duration::from_nanos(1); @@ -105,7 +107,6 @@ pub fn from_str(string: &str, allow_suffixes: bool) -> Result return Ok(NANOSECOND_DURATION); } - const NANOS_PER_SEC: u32 = 1_000_000_000; let whole_secs: u64 = match (&nanos_bi / NANOS_PER_SEC).try_into() { Ok(whole_secs) => whole_secs, Err(_) => return Ok(Duration::MAX), diff --git a/src/uucore/src/lib/features/safe_traversal.rs b/src/uucore/src/lib/features/safe_traversal.rs index 0b7d4f710..9fc8fb244 100644 --- a/src/uucore/src/lib/features/safe_traversal.rs +++ b/src/uucore/src/lib/features/safe_traversal.rs @@ -1100,11 +1100,12 @@ mod tests { #[test] fn test_open_file_at_creates_file() { + use std::io::Write; + let temp_dir = TempDir::new().unwrap(); let dir_fd = DirFd::open(temp_dir.path(), SymlinkBehavior::Follow).unwrap(); let mut file = dir_fd.open_file_at(OsStr::new("new_file.txt")).unwrap(); - use std::io::Write; file.write_all(b"test content").unwrap(); let content = fs::read_to_string(temp_dir.path().join("new_file.txt")).unwrap(); @@ -1113,13 +1114,14 @@ mod tests { #[test] fn test_open_file_at_truncates_existing() { + use std::io::Write; + let temp_dir = TempDir::new().unwrap(); let file_path = temp_dir.path().join("existing.txt"); fs::write(&file_path, "old content that is longer").unwrap(); let dir_fd = DirFd::open(temp_dir.path(), SymlinkBehavior::Follow).unwrap(); let mut file = dir_fd.open_file_at(OsStr::new("existing.txt")).unwrap(); - use std::io::Write; file.write_all(b"new").unwrap(); drop(file); diff --git a/src/uucore/src/lib/macros.rs b/src/uucore/src/lib/macros.rs index bd234768e..890300281 100644 --- a/src/uucore/src/lib/macros.rs +++ b/src/uucore/src/lib/macros.rs @@ -89,9 +89,10 @@ macro_rules! show( ($err:expr) => ({ #[allow(unused_imports)] use $crate::error::UError; + use std::io::Write as _; + let e = $err; $crate::error::set_exit_code(e.code()); - use std::io::Write as _; let _ = writeln!(std::io::stderr().lock(), "{}: {e}", $crate::util_name()); }) ); diff --git a/tests/by-util/test_pinky.rs b/tests/by-util/test_pinky.rs index 98eefc781..03447fd04 100644 --- a/tests/by-util/test_pinky.rs +++ b/tests/by-util/test_pinky.rs @@ -85,12 +85,6 @@ fn test_short_format_i() { #[test] #[cfg(not(target_os = "openbsd"))] fn test_lookup() { - let args = ["--lookup"]; - let ts = TestScenario::new(util_name!()); - let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(&ts, &[])).stdout_move_str(); - let v_actual: Vec<&str> = actual.split_whitespace().collect(); - let v_expect: Vec<&str> = expect.split_whitespace().collect(); // The "Idle" field (index 3 in header) contains a dynamic time value that can change // between when the two commands run (e.g., "00:09" vs "00:10"), causing flaky tests. // We filter out values matching the idle time pattern (HH:MM format) to avoid race conditions. @@ -120,6 +114,13 @@ fn test_lookup() { .map(|(_, s)| (*s).to_string()) .collect() } + + let args = ["--lookup"]; + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &[])).stdout_move_str(); + let v_actual: Vec<&str> = actual.split_whitespace().collect(); + let v_expect: Vec<&str> = expect.split_whitespace().collect(); let v_actual_filtered = filter_idle_times(&v_actual); let v_expect_filtered = filter_idle_times(&v_expect); assert_eq!(v_actual_filtered, v_expect_filtered); diff --git a/tests/by-util/test_wc.rs b/tests/by-util/test_wc.rs index 023e577b1..62f100b42 100644 --- a/tests/by-util/test_wc.rs +++ b/tests/by-util/test_wc.rs @@ -794,9 +794,6 @@ fn test_files0_stops_after_stdout_write_error() { #[test] fn files0_from_dir() { - // On Unix, `read(open("."))` fails. On Windows, `open(".")` fails. Thus, the errors happen in - // different contexts. On WASI, the error string may differ (e.g., "Bad file descriptor"). - let wasm = std::env::var("UUTESTS_WASM_RUNNER").is_ok(); #[cfg(not(windows))] macro_rules! dir_err { ($p:literal) => { @@ -814,6 +811,10 @@ fn files0_from_dir() { #[cfg(not(windows))] const DOT_ERR: &str = dir_err!("."); + // On Unix, `read(open("."))` fails. On Windows, `open(".")` fails. Thus, the errors happen in + // different contexts. On WASI, the error string may differ (e.g., "Bad file descriptor"). + let wasm = std::env::var("UUTESTS_WASM_RUNNER").is_ok(); + let cmd = new_ucmd!().args(&["--files0-from=dir with spaces"]).fails(); if wasm { cmd.stderr_contains("wc: 'dir with spaces': read error:"); @@ -874,6 +875,8 @@ fn test_invalid_byte_sequence_word_count() { #[test] #[cfg_attr(wasi_runner, ignore = "WASI sandbox: host paths not visible")] fn test_simd_respects_glibc_tunables() { + use std::fmt::Write as _; + // Ensure debug output reflects that SIMD paths are disabled via GLIBC_TUNABLES let debug_output = new_ucmd!() .args(&["-l", "--debug", "/dev/null"]) @@ -892,7 +895,6 @@ fn test_simd_respects_glibc_tunables() { // WC results should be identical with and without GLIBC_TUNABLES overrides let sample_sizes = [0usize, 1, 7, 128, 513, 999]; - use std::fmt::Write as _; for &lines in &sample_sizes { let content: String = (0..lines).fold(String::new(), |mut acc, i| { // Build the input buffer efficiently without allocating per line.