Skip to main content

Module ffi

Module ffi 

Source
Expand description

Thread-local last-error storage and the panic guard, for a C ABI that returns sentinels rather than error values.

§The shape this supports

A C entry point cannot return a Rust Result, so the family’s libraries return null or a sentinel and record why separately, to be read by <lib>_last_error() and <lib>_last_error_kind(). Three things have to hold for that to be trustworthy:

  • Message and kind move together. A message paired with a stale kind is worse than no kind at all, because it looks authoritative. LastErrorSlot::set writes both.
  • Nothing unwinds across the boundary. Unwinding out of extern "C" is undefined behaviour, so every entry point wraps its body — see catch.
  • Classification survives to the boundary. Rendering an error to a string early discards the reason. Closures therefore carry FfiError, not String.

§Why the slot is yours, not ours

LastErrorSlot is a type you place in your own thread_local!, rather than storage this crate owns. That is deliberate and load-bearing.

Each library ships as its own cdylib, so today each has its own statics. But this crate is linked into all of them, and a Rust binary depending on two of them would share one copy — at which point a single shared static would make unpdf_last_error() return whatever the preceding undoc call recorded. Isolation cannot rest on how consumers happen to link; declaring the slot in the consuming crate makes it structural.

use unparser_shared::ffi::LastErrorSlot;

thread_local! {
    static LAST_ERROR: LastErrorSlot = const { LastErrorSlot::new() };
}

unparser_shared::export_last_error_abi!(LAST_ERROR, demo_last_error, demo_last_error_kind);

Structs§

LastErrorSlot
The last failure recorded on this thread, and its classification.

Functions§

c_str_utf8⚠
Read a non-null C string argument as &str, classifying a non-UTF-8 one.
catch
Run body, turning a panic into kind::PANIC instead of unwinding.
invalid_argument
A null or non-UTF-8 argument.
invalid_output
A result that cannot cross the ABI because it holds an interior NUL byte.

Type Aliases§

FfiError
A failure on its way out of an entry point: why it failed, and what to say about it.