Skip to main content

forme/
error.rs

1//! Structured error types for the Forme rendering engine.
2//!
3//! Three variants cover the real error sources: JSON parsing, font loading,
4//! and layout/PDF generation failures.
5
6use std::fmt;
7
8/// The unified error type returned by all public Forme API functions.
9#[derive(Debug)]
10pub enum FormeError {
11    /// JSON input failed to parse as a valid Forme document.
12    ParseError {
13        source: serde_json::Error,
14        hint: String,
15    },
16    /// A font could not be loaded, parsed, or embedded.
17    FontError(String),
18    /// Layout or PDF generation failed.
19    RenderError(String),
20    /// Template expression evaluation failed.
21    TemplateError(String),
22}
23
24impl fmt::Display for FormeError {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            FormeError::ParseError { source, hint } => {
28                write!(f, "Failed to parse document: {}", source)?;
29                if !hint.is_empty() {
30                    write!(f, "\n  Hint: {}", hint)?;
31                }
32                Ok(())
33            }
34            FormeError::FontError(msg) => write!(f, "Font error: {}", msg),
35            FormeError::RenderError(msg) => write!(f, "Render error: {}", msg),
36            FormeError::TemplateError(msg) => write!(f, "Template error: {}", msg),
37        }
38    }
39}
40
41impl std::error::Error for FormeError {
42    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
43        match self {
44            FormeError::ParseError { source, .. } => Some(source),
45            _ => None,
46        }
47    }
48}
49
50impl From<serde_json::Error> for FormeError {
51    fn from(e: serde_json::Error) -> Self {
52        let hint = match e.classify() {
53            serde_json::error::Category::Syntax => {
54                "Check for trailing commas, missing quotes, or unescaped characters.".to_string()
55            }
56            serde_json::error::Category::Data => {
57                "The JSON is valid but doesn't match the Forme document schema. Check field names and types.".to_string()
58            }
59            serde_json::error::Category::Eof => {
60                "Unexpected end of input — is the JSON truncated?".to_string()
61            }
62            serde_json::error::Category::Io => String::new(),
63        };
64        FormeError::ParseError { source: e, hint }
65    }
66}