use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
use quarto_source_map::{SourceContext, SourceInfo};
struct CountingAllocator;
static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
ALLOCATED.fetch_add(layout.size(), Ordering::Relaxed);
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
}
#[global_allocator]
static GLOBAL: CountingAllocator = CountingAllocator;
fn one_megabyte_file() -> String {
let line = "- item with some words, `code`, and *emphasis* on it\n";
line.repeat((1 << 20) / line.len() + 1)
}
#[test]
fn map_offset_on_in_memory_file_allocates_a_bounded_amount() {
let content = one_megabyte_file();
let total = content.len();
let mut ctx = SourceContext::new();
let file_id = ctx.add_file("big.qmd".to_string(), Some(content));
let info = SourceInfo::original(file_id, 0, total);
const CALLS: usize = 1000;
let before = ALLOCATED.load(Ordering::Relaxed);
for i in 0..CALLS {
let offset = (i * 7919) % total;
let mapped = info.map_offset(offset, &ctx).expect("offset is in bounds");
assert_eq!(mapped.location.offset, offset);
}
let allocated = ALLOCATED.load(Ordering::Relaxed) - before;
const BUDGET: usize = 64 * 1024;
assert!(
allocated < BUDGET,
"{CALLS} map_offset calls on a {total}-byte in-memory file allocated \
{allocated} bytes (budget {BUDGET}); map_offset must borrow the \
stored content, not clone it"
);
}