use std::io::Write;
use std::time::{Duration, Instant};
use text_document::{MoveMode, TextDocument};
macro_rules! row {
($($arg:tt)*) => {{
println!($($arg)*);
let _ = std::io::stdout().flush();
}};
}
const LINE: &str = "2026-07-16T12:00:00Z INFO worker: processed batch id=1234 in 42ms";
const SIZES: [usize; 3] = [1_000, 10_000, 100_000];
const APPEND_BATCH: usize = 20;
const REPS: usize = 3;
fn make_doc(lines: usize) -> TextDocument {
let text: String = (0..lines).map(|_| LINE).collect::<Vec<_>>().join("\n");
let doc = TextDocument::new();
doc.set_plain_text(&text).unwrap();
doc
}
fn median(mut xs: Vec<Duration>) -> Duration {
xs.sort_unstable();
xs[xs.len() / 2]
}
fn main() {
row!();
row!("text-document — what a streaming log view pays per line");
row!("{:-<92}", "");
row!(
"{:>9} {:>16} {:>18} {:>14} {:>16}",
"N",
"append_line",
"append_line FAST",
"truncate",
"truncate FAST"
);
row!(
"{:>9} {:>16} {:>18} {:>14} {:>16}",
"",
"(per line)",
"(per line)",
"(20 lines)",
"(20 lines)"
);
row!("{:-<92}", "");
for n in SIZES {
let append = median(
(0..REPS)
.map(|_| {
let doc = make_doc(n);
let start = Instant::now();
for _ in 0..APPEND_BATCH {
let cursor = doc.cursor_at(doc.character_count());
cursor.insert_block().unwrap();
cursor.insert_text(LINE).unwrap();
}
start.elapsed()
})
.collect(),
) / APPEND_BATCH as u32;
let append_held = median(
(0..REPS)
.map(|_| {
let doc = make_doc(n);
let cursor = doc.cursor_at(doc.character_count());
let start = Instant::now();
for _ in 0..APPEND_BATCH {
cursor.insert_block().unwrap();
cursor.insert_text(LINE).unwrap();
}
start.elapsed()
})
.collect(),
) / APPEND_BATCH as u32;
let count = median(
(0..REPS)
.map(|_| {
let doc = make_doc(n);
let start = Instant::now();
for _ in 0..APPEND_BATCH {
std::hint::black_box(doc.block_count());
}
start.elapsed()
})
.collect(),
) / APPEND_BATCH as u32;
let truncate = median(
(0..REPS)
.map(|_| {
let doc = make_doc(n);
let cut = doc.block_by_number(APPEND_BATCH).unwrap().position();
let cursor = doc.cursor_at(0);
let start = Instant::now();
cursor.set_position(cut, MoveMode::KeepAnchor);
cursor.remove_selected_text().unwrap();
start.elapsed()
})
.collect(),
);
let fast_append = median(
(0..REPS)
.map(|_| {
let doc = make_doc(n);
let start = Instant::now();
for _ in 0..APPEND_BATCH {
doc.append_line(LINE).unwrap();
}
start.elapsed()
})
.collect(),
) / APPEND_BATCH as u32;
let fast_truncate = median(
(0..REPS)
.map(|_| {
let doc = make_doc(n);
let start = Instant::now();
doc.truncate_front(APPEND_BATCH).unwrap();
start.elapsed()
})
.collect(),
);
std::hint::black_box((append_held, count));
row!(
"{:>9} {:>16} {:>18} {:>14} {:>16}",
n,
format!("{append:?}"),
format!("{fast_append:?}"),
format!("{truncate:?}"),
format!("{fast_truncate:?}")
);
}
row!("{:-<92}", "");
row!("append_line = cursor_at(character_count()) + insert_block + insert_text");
row!("append (held cur) = insert_block + insert_text, end located once beforehand");
row!("block_count = the scrollback-cap check a viewer runs every line");
row!("truncate_front = select [0, block 20) + remove_selected_text");
row!();
}