gaze_document/render/mod.rs
1//! Renderer contract surface.
2//!
3//! Concrete renderers (redacted preview PNG, redacted PDF) land behind the
4//! `render-image` feature in a follow-up PR. This module reserves the trait
5//! shape and a fail-loud default so adopters can wire trait objects without
6//! risking silent zero-output rendering (Axis 1 fail-closed).
7
8use crate::DocumentError;
9
10/// Adapter contract for output renderers.
11///
12/// Renderers consume a [`crate::SafeBundle`] and produce a binary payload.
13/// Implementations must respect the manifest contract — every byte they
14/// emit must be either tokenized or non-PII per the bundle's
15/// [`gaze::Manifest`].
16pub trait Renderer {
17 /// Render the bundle into a byte payload (PNG, PDF, ...).
18 ///
19 /// # Errors
20 /// Implementations return [`DocumentError`] on backend failure.
21 fn render(&self, bundle: &crate::SafeBundle) -> Result<Vec<u8>, DocumentError>;
22}
23
24/// Reserved fail-loud renderer.
25///
26/// Every call returns [`DocumentError::NotImplemented`] so accidental
27/// wiring is caught at the call site.
28#[non_exhaustive]
29pub struct PendingRenderer {
30 _private: (),
31}
32
33impl PendingRenderer {
34 /// Build the fail-loud renderer.
35 ///
36 /// # Errors
37 /// Always returns [`DocumentError::NotImplemented`]. The placeholder
38 /// exists so adopters wiring a trait object without a concrete
39 /// renderer fail at construction time rather than producing silent
40 /// zero-output (Axis 1 fail-closed).
41 pub fn new() -> Result<Self, DocumentError> {
42 Err(DocumentError::NotImplemented(
43 "PendingRenderer::new (wire a concrete Renderer impl)",
44 ))
45 }
46}
47
48impl Renderer for PendingRenderer {
49 fn render(&self, _bundle: &crate::SafeBundle) -> Result<Vec<u8>, DocumentError> {
50 Err(DocumentError::NotImplemented(
51 "PendingRenderer::render (wire a concrete Renderer impl)",
52 ))
53 }
54}