#[derive(Debug, Clone, PartialEq)]
pub struct Compressed {
pub text: String,
pub saved: u64,
}
pub trait OutputCompressor: Send + Sync {
fn matches(&self, cmd: &str) -> bool;
fn compress(&self, raw: &str) -> Compressed;
}
pub fn estimate_tokens(s: &str) -> u64 {
(s.len() as u64).div_ceil(4)
}
pub struct Optimizer {
compressors: Vec<Box<dyn OutputCompressor>>,
enabled: bool,
}
impl Optimizer {
pub fn new(enabled: bool) -> Self {
Optimizer {
compressors: vec![Box::new(GenericCompressor::new(200))],
enabled,
}
}
pub fn register(&mut self, c: Box<dyn OutputCompressor>) {
let fallback_idx = self.compressors.len() - 1;
self.compressors.insert(fallback_idx, c);
}
pub fn apply(&self, cmd: &str, raw: &str) -> Compressed {
if !self.enabled {
return Compressed {
text: raw.to_string(),
saved: 0,
};
}
for c in &self.compressors {
if c.matches(cmd) {
return c.compress(raw);
}
}
Compressed {
text: raw.to_string(),
saved: 0,
}
}
}
struct GenericCompressor {
max_lines: usize,
}
impl GenericCompressor {
fn new(max_lines: usize) -> Self {
GenericCompressor { max_lines }
}
}
impl OutputCompressor for GenericCompressor {
fn matches(&self, _cmd: &str) -> bool {
true
}
fn compress(&self, raw: &str) -> Compressed {
let deduped = dedupe_consecutive(raw);
let text = truncate_middle(&deduped, self.max_lines);
let saved = estimate_tokens(raw).saturating_sub(estimate_tokens(&text));
Compressed { text, saved }
}
}
fn dedupe_consecutive(raw: &str) -> String {
let mut out: Vec<String> = Vec::new();
let mut prev: Option<&str> = None;
let mut run = 0usize;
let flush = |out: &mut Vec<String>, line: &str, run: usize| {
out.push(line.to_string());
if run > 1 {
out.push(format!("... (x{run})"));
}
};
for line in raw.lines() {
match prev {
Some(p) if p == line => run += 1,
Some(p) => {
flush(&mut out, p, run);
run = 1;
}
None => run = 1,
}
prev = Some(line);
}
if let Some(p) = prev {
flush(&mut out, p, run);
}
out.join("\n")
}
fn truncate_middle(text: &str, max_lines: usize) -> String {
let lines: Vec<&str> = text.lines().collect();
if lines.len() <= max_lines {
return text.to_string();
}
let keep = max_lines / 2;
let omitted = lines.len() - keep * 2;
let mut out: Vec<String> = Vec::with_capacity(keep * 2 + 1);
out.extend(lines[..keep].iter().map(|s| s.to_string()));
out.push(format!("... ({omitted} lines elided by optimizer) ..."));
out.extend(lines[lines.len() - keep..].iter().map(|s| s.to_string()));
out.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dedupe_collapses_runs() {
let raw = "a\nb\nb\nb\nc";
assert_eq!(dedupe_consecutive(raw), "a\nb\n... (x3)\nc");
}
#[test]
fn generic_compressor_saves_tokens_on_dupes() {
let raw = "same line\n".repeat(50);
let opt = Optimizer::new(true);
let out = opt.apply("some-cmd", &raw);
assert!(out.saved > 0);
assert!(out.text.contains("(x"));
}
#[test]
fn disabled_optimizer_is_passthrough() {
let raw = "x\nx\nx";
let opt = Optimizer::new(false);
let out = opt.apply("cmd", raw);
assert_eq!(out.text, raw);
assert_eq!(out.saved, 0);
}
#[test]
fn truncate_keeps_head_and_tail() {
let raw: String = (0..1000).map(|i| format!("line{i}\n")).collect();
let out = truncate_middle(&raw, 100);
assert!(out.contains("line0"));
assert!(out.contains("line999"));
assert!(out.contains("elided by optimizer"));
}
}