use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
use std::time::Instant;
use crate::{ExtractOptions, PdfDocument};
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct BatchItem {
pub markdown: Result<String, String>,
pub ms: u128,
}
#[doc(hidden)]
pub fn markdown_of_bytes_with_options(
bytes: Vec<u8>,
options: &ExtractOptions,
) -> Result<String, String> {
let doc = PdfDocument::open(bytes).map_err(|err| format!("open: {err}"))?;
let (blocks, rules) = doc
.extract_blocks_and_rules(options)
.map_err(|err| format!("blocks: {err}"))?;
Ok(crate::markdown::to_markdown_with_rules(&blocks, &rules))
}
#[doc(hidden)]
pub fn markdown_of_bytes(bytes: Vec<u8>) -> Result<String, String> {
markdown_of_bytes_with_options(bytes, &ExtractOptions::default())
}
#[doc(hidden)]
pub fn batch_markdown<F>(count: usize, jobs: usize, read: F) -> Vec<BatchItem>
where
F: Fn(usize) -> Result<Vec<u8>, String> + Sync,
{
let next = AtomicUsize::new(0);
let done: Mutex<Vec<(usize, BatchItem)>> = Mutex::new(Vec::with_capacity(count));
std::thread::scope(|scope| {
for _ in 0..jobs.max(1) {
scope.spawn(|| loop {
let i = next.fetch_add(1, Ordering::Relaxed);
if i >= count {
break;
}
let started = Instant::now();
let markdown = read(i).and_then(markdown_of_bytes);
let item = BatchItem {
markdown,
ms: started.elapsed().as_millis(),
};
if let Ok(mut done) = done.lock() {
done.push((i, item));
}
});
}
});
let mut done = done.into_inner().unwrap_or_default();
done.sort_by_key(|(i, _)| *i);
done.into_iter().map(|(_, item)| item).collect()
}