From 9a25bdea37f0438209432d6e6d6cf640ff72acf8 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Tue, 2 Sep 2025 11:27:50 -0300 Subject: [PATCH] refactor: Optimize filter plugins to read in chunks of PIPESIZE Co-authored-by: aider (openai/andrew/openrouter/deepseek/deepseek-chat-v3.1) --- src/filter_plugin/head.rs | 12 ++++++++---- src/filter_plugin/skip.rs | 28 +++++++++++++--------------- src/filter_plugin/strip_ansi.rs | 16 +++++++++++++--- src/filter_plugin/tail.rs | 3 ++- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/filter_plugin/head.rs b/src/filter_plugin/head.rs index c6b20f1..27d1893 100644 --- a/src/filter_plugin/head.rs +++ b/src/filter_plugin/head.rs @@ -1,5 +1,6 @@ use super::FilterPlugin; use std::io::{Result, Read, Write, BufRead}; +use crate::common::PIPESIZE; pub struct HeadBytesFilter { remaining: usize, @@ -19,10 +20,13 @@ impl FilterPlugin for HeadBytesFilter { return Ok(()); } - // Read only up to remaining bytes - let mut buffer = vec![0; self.remaining]; - let bytes_read = reader.read(&mut buffer)?; - if bytes_read > 0 { + let mut buffer = vec![0; PIPESIZE]; + while self.remaining > 0 { + let to_read = std::cmp::min(self.remaining, PIPESIZE); + let bytes_read = reader.read(&mut buffer[..to_read])?; + if bytes_read == 0 { + break; + } writer.write_all(&buffer[..bytes_read])?; self.remaining -= bytes_read; } diff --git a/src/filter_plugin/skip.rs b/src/filter_plugin/skip.rs index 2de1537..a83b195 100644 --- a/src/filter_plugin/skip.rs +++ b/src/filter_plugin/skip.rs @@ -1,5 +1,6 @@ use super::FilterPlugin; use std::io::{Result, Read, Write, BufRead, Seek}; +use crate::common::PIPESIZE; pub struct SkipBytesFilter { remaining: usize, @@ -15,22 +16,12 @@ impl SkipBytesFilter { impl FilterPlugin for SkipBytesFilter { fn filter(&mut self, reader: &mut R, writer: &mut W) -> Result<()> { - // Try to use seek if the reader supports it + // Skip bytes in chunks if self.remaining > 0 { - // Create a mutable reference that we can try to cast to &mut dyn Seek - let any_reader: &mut dyn std::io::Read = reader; - // We need to use unsafe code to perform the cast, but let's find a safer way - - // Instead, we can use a helper function that uses a trait object - // For now, we'll use a different approach: check if the concrete type implements Seek - // Since we can't easily do that at runtime, we'll use a different strategy - - // Let's read a small buffer at a time to be efficient - const BUFFER_SIZE: usize = 8192; + let mut buffer = vec![0; PIPESIZE]; while self.remaining > 0 { - let to_read = std::cmp::min(self.remaining, BUFFER_SIZE); - let mut buffer = vec![0; to_read]; - let bytes_read = reader.read(&mut buffer)?; + let to_read = std::cmp::min(self.remaining, PIPESIZE); + let bytes_read = reader.read(&mut buffer[..to_read])?; if bytes_read == 0 { break; } @@ -39,7 +30,14 @@ impl FilterPlugin for SkipBytesFilter { } // Copy the remaining data - std::io::copy(reader, writer)?; + let mut buffer = vec![0; PIPESIZE]; + loop { + let bytes_read = reader.read(&mut buffer)?; + if bytes_read == 0 { + break; + } + writer.write_all(&buffer[..bytes_read])?; + } Ok(()) } } diff --git a/src/filter_plugin/strip_ansi.rs b/src/filter_plugin/strip_ansi.rs index 3acb52a..8aa6dc7 100644 --- a/src/filter_plugin/strip_ansi.rs +++ b/src/filter_plugin/strip_ansi.rs @@ -1,5 +1,6 @@ use std::io::{Result, Read, Write}; use strip_ansi_escapes::strip as strip_ansi_escapes; +use crate::common::PIPESIZE; use super::FilterPlugin; @@ -13,9 +14,18 @@ impl StripAnsiFilter { impl FilterPlugin for StripAnsiFilter { fn filter(&mut self, reader: &mut R, writer: &mut W) -> Result<()> { - let mut data = Vec::new(); - reader.read_to_end(&mut data)?; - let stripped = strip_ansi_escapes(&data); + let mut buffer = vec![0; PIPESIZE]; + let mut processed_data = Vec::new(); + + loop { + let bytes_read = reader.read(&mut buffer)?; + if bytes_read == 0 { + break; + } + processed_data.extend_from_slice(&buffer[..bytes_read]); + } + + let stripped = strip_ansi_escapes(&processed_data); writer.write_all(&stripped)?; Ok(()) } diff --git a/src/filter_plugin/tail.rs b/src/filter_plugin/tail.rs index 0e5b6f2..8927107 100644 --- a/src/filter_plugin/tail.rs +++ b/src/filter_plugin/tail.rs @@ -1,6 +1,7 @@ use super::FilterPlugin; use std::io::{Result, Read, Write, BufRead}; use std::collections::VecDeque; +use crate::common::PIPESIZE; pub struct TailBytesFilter { buffer: VecDeque, @@ -18,7 +19,7 @@ impl TailBytesFilter { impl FilterPlugin for TailBytesFilter { fn filter(&mut self, reader: &mut R, writer: &mut W) -> Result<()> { - let mut temp_buffer = vec![0; 8192]; + let mut temp_buffer = vec![0; PIPESIZE]; loop { let bytes_read = reader.read(&mut temp_buffer)?; if bytes_read == 0 {