Skip to content
Open
Changes from all commits
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
34 changes: 34 additions & 0 deletions src/uu/wc/src/wc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,30 @@ 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;
};

if rustix::fs::FileType::from_raw_mode(stat.st_mode) == rustix::fs::FileType::RegularFile {
return Some(stat.st_size as usize);
}
None
}
#[cfg(not(unix))]
{
None // TODO: Implement Windows support
}
}
struct Settings<'a> {
show_bytes: bool,
show_chars: bool,
Expand Down Expand Up @@ -482,6 +506,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