Skip to content
32 changes: 32 additions & 0 deletions src/uu/wc/src/wc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,28 @@ use crate::{
/// The minimum character width for formatting counts when reading from stdin.
const MINIMUM_WIDTH: usize = 7;

/// Returns the byte size of stdin if it is a regular file (e.g. `wc -c < file`).
/// Returns `None` for pipes, terminals, sockets, etc. so we fall back to normal counting.
fn try_get_stdin_size() -> Option<usize> {
#[cfg(unix)]
{
use rustix::fd::AsFd;
let stdin = io::stdin();
let fd = stdin.as_fd();
let Ok(stat) = rustix::fs::fstat(fd) else {
return None;
};
let file_type = rustix::fs::FileType::from_raw_mode(stat.st_mode);
if file_type == rustix::fs::FileType::RegularFile {
return Some(stat.st_size as usize);
}
None
}
#[cfg(not(unix))]
{
None
}
}
struct Settings<'a> {
show_bytes: bool,
show_chars: bool,
Expand Down Expand Up @@ -483,6 +505,16 @@ fn word_count_from_reader<T: WordCountable>(

// show_bytes
(true, false, false, false, false) => {
// Fast path: if stdin is a regular file, get size from metadata (no reading needed)
if let Some(bytes) = try_get_stdin_size() {
return (
WordCount {
bytes,
..WordCount::default()
},
None,
);
}
// Fast path when only show_bytes is true.
let (bytes, error) = count_bytes_fast(&mut reader);
(
Expand Down
Loading