ajrcarey / pdfium-render

A high-level idiomatic Rust wrapper around Pdfium, the C++ PDF library used by the Google Chromium project.
https://crates.io/crates/pdfium-render
Other
364 stars 59 forks source link

Using pdfium with axum #172

Open danwritecode opened 4 days ago

danwritecode commented 4 days ago

Hey there! This crate has been amazing and it's allowed me to do exactly what i need, however, I'm using pdfium in a web server environment with Axum and I run into the below issue.

rustc: `*mut pdfium_render::bindgen::fpdf_document_t__` cannot be sent between threads safely
 within `impl std::future::Future<Output = Result<(), AppError>>`, the trait `Send` is not implemented for `*mut pdfium_render::bindgen::fpdf_document_t__`, which is required by `impl std::future::Future<Output = Result<(), AppError>>: Send` [E0277]

I have "sync" enabled: pdfium-render = { version = "0.8.26", features = ["sync"] }

Currently exploring a different solution entirely, but pdfium is by far the most robust solution available in the rust ecosystem and this library is really a joy to use.

Appreciate any guidance!

ajrcarey commented 3 days ago

Hi @danwritecode , thank you for reporting the issue. I know you already know this, but I feel compelled to reiterate that Pdfium is not thread-safe. So my instinct is that it's probably not possible to safely do what you're trying to do.

That said, if you want to try and do it anyway, I suggest git clone-ing this repo, adding Sync and Send impls for FPDF_DOCUMENT to src/pdf/document.rs as per below, and trying it out in your environment by taking pdfium-render as a local path dependency in your Cargo.toml. I'd be curious as to whether it works or not. If it does, then we could look at merging those additional impls into this repo.

Currently, the very bottom of document.rs has:

#[cfg(feature = "sync")]
unsafe impl<'a> Sync for PdfDocument<'a> {}

#[cfg(feature = "sync")]
unsafe impl<'a> Send for PdfDocument<'a> {}

You want to try extending this to also include:

#[cfg(feature = "sync")]
unsafe impl<'a> Sync for FPDF_DOCUMENT {}

#[cfg(feature = "sync")]
unsafe impl<'a> Send for FPDF_DOCUMENT {}

(FPDF_DOCUMENT is just a type alias for fpdf_document_t.)

I will leave this issue open for the next week or so to give you a chance to try it out and report back, if you wish.

ajrcarey commented 3 days ago

(PS it's possible, perhaps likely, that this will result in a cascade where Sync and Send also need to be implemented for child types of FPDF_DOCUMENT such as FPDF_PAGE, etc.)

danwritecode commented 3 days ago

Awesome, I appreciate the response! I will fork it and give it a shot and report back with my findings.

ajrcarey commented 3 days ago

Even if it doesn't work (and if I had to guess, I'd guess it won't), you may be able to work around it by lifting your Pdfium, PdfiumLibraryBindings, and PdfDocument object instances into a Mutex or similar and accessing them that way using a more traditional locking approach rather than passing them around as function arguments.