Skip to main content

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}