Skip to main content

lightweight_pdf/
lib.rs

1//! Public facade for `lightweight-pdf`: re-exports the `lightweight-pdf-core` builder API
2//! and adds `Document::render()` (ADR-002 — this is the crate users add to
3//! `Cargo.toml`, the place `render()` becomes public).
4
5mod fonts;
6mod images;
7mod render;
8#[cfg(all(target_arch = "wasm32", feature = "wasm"))]
9mod wasm_bindings;
10
11pub use fonts::FontRegistry;
12pub use images::ImageEmbedError;
13pub use lightweight_pdf_core::*;
14pub use lightweight_pdf_fonts::FontError;
15pub use lightweight_pdf_layout::{LayoutWarning, LayoutWarningKind};
16pub use render::{DocumentExt, RenderError};
17#[cfg(all(target_arch = "wasm32", feature = "wasm"))]
18pub use wasm_bindings::{LightweightPdf, RenderResult};
19
20#[cfg(all(feature = "wasm-size-probe", not(feature = "default-fonts")))]
21compile_error!(
22    "wasm-size-probe needs a font source: enable `default-fonts` alongside it (see plan/00a-contracts-and-artifacts.md, point 2)"
23);
24
25/// Internal, non-public measurement export (`plan/00a-contracts-and-artifacts.md`
26/// point 1): renders a small but complete document end-to-end so the real
27/// render path isn't dead-code-eliminated from the size measurement.
28/// Independent of the `wasm` feature's actual `wasm_bindings` module
29/// (ADR-009 v2, issue #22) — this probe exists purely to catch dead-code
30/// elimination regressions in the size measurement itself, not to be a
31/// runtime API.
32#[cfg(feature = "wasm-size-probe")]
33#[no_mangle]
34pub extern "C" fn lightweight_pdf_wasm_size_probe() -> i32 {
35    let mut doc = Document::new(PageFormat::A4);
36    doc.add(Text::new("Hallo Rechnung").size(18.0).bold());
37    let cell = |s: &str| Text::new(s).size(10.0);
38    doc.add(Row::new().gap(8.0).child(cell("Menge")).child(cell("Preis")));
39    doc.add(Line::new());
40    match doc.render() {
41        // `bytes` comes from rendering the small, fixed document literally
42        // constructed above (not attacker/caller-supplied input), so its
43        // length is bounded far below `i32::MAX` in practice — `unwrap_or`
44        // keeps that a non-panicking fallback rather than an `.expect()` on
45        // this `pub extern "C"` FFI boundary.
46        Ok(bytes) => i32::try_from(bytes.len()).unwrap_or(i32::MAX),
47        Err(_) => -1,
48    }
49}