use std::alloc::{GlobalAlloc, Layout, System};
use std::cell::Cell;
#[path = "support/synthetic_pdf.rs"]
mod synthetic_pdf;
struct PerThread;
thread_local! {
static CUR: Cell<isize> = const { Cell::new(0) };
static PEAK: Cell<isize> = const { Cell::new(0) };
}
fn track(delta: isize) {
let _ = CUR.try_with(|c| {
let v = c.get() + delta;
c.set(v);
let _ = PEAK.try_with(|p| p.set(p.get().max(v)));
});
}
unsafe impl GlobalAlloc for PerThread {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
track(l.size() as isize);
unsafe { System.alloc(l) }
}
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
track(-(l.size() as isize));
unsafe { System.dealloc(p, l) }
}
unsafe fn realloc(&self, p: *mut u8, l: Layout, n: usize) -> *mut u8 {
track(n as isize - l.size() as isize);
unsafe { System.realloc(p, l, n) }
}
}
#[global_allocator]
static ALLOC: PerThread = PerThread;
fn peak_of<T>(f: impl FnOnce() -> T) -> (T, usize) {
let start = CUR.with(Cell::get);
PEAK.with(|p| p.set(start));
let out = f();
(out, (PEAK.with(Cell::get) - start).max(0) as usize)
}
const PAGES: usize = 40;
#[test]
fn a_page_window_does_not_pay_for_the_whole_document() {
let bytes = synthetic_pdf::dense_table_pdf(PAGES, 20, 10);
let (full, full_peak) =
peak_of(|| docling_pdf::convert_text_layer_pages(&bytes, "t.pdf", None).unwrap());
let (one, one_peak) = peak_of(|| {
docling_pdf::convert_text_layer_pages(&bytes, "t.pdf", Some((PAGES / 2, PAGES / 2)))
.unwrap()
});
eprintln!("whole document: peak {full_peak} B; one-page window: peak {one_peak} B");
assert!(full.nodes.len() > PAGES * 200, "{} nodes", full.nodes.len());
assert!(!one.nodes.is_empty() && one.nodes.len() * 10 < full.nodes.len());
assert!(
one_peak * 4 < full_peak,
"one-page window peaked at {one_peak} B, the whole document at {full_peak} B"
);
}
#[test]
fn the_whole_document_peak_is_its_output_plus_one_page() {
let bytes = synthetic_pdf::dense_table_pdf(PAGES, 20, 10);
let start = CUR.with(Cell::get);
let (doc, peak) =
peak_of(|| docling_pdf::convert_text_layer_pages(&bytes, "t.pdf", None).unwrap());
let output = (CUR.with(Cell::get) - start).max(1) as usize;
eprintln!("peak {peak} B, output {output} B");
assert!(doc.nodes.len() > PAGES * 200);
assert!(
peak < 2 * output,
"peaked at {peak} B for a {output} B document"
);
}
#[test]
fn page_windows_keep_the_vestigial_and_range_verdicts() {
let bytes = synthetic_pdf::dense_table_pdf(3, 2, 2);
assert!(docling_pdf::convert_text_layer_pages(&bytes, "t.pdf", Some((9, 9))).is_err());
let doc = docling_pdf::convert_text_layer_pages(&bytes, "t.pdf", Some((2, 2))).unwrap();
let md = doc.export_to_markdown();
assert!(md.contains("Table 2") && !md.contains("Table 1") && !md.contains("Table 3"));
let vestigial = synthetic_pdf::dense_table_pdf(3, 0, 0);
for window in [None, Some((2, 2)), Some((9, 9))] {
let doc = docling_pdf::convert_text_layer_pages(&vestigial, "t.pdf", window).unwrap();
assert!(doc.nodes.is_empty(), "{window:?}");
}
}