Skip to main content

adobe_font_metrics/
error.rs

1use std::{error::Error, fmt};
2
3/// Errors returned by [`crate::parse`]. Line numbers are 1-based.
4///
5/// # Examples
6///
7/// ```
8/// use adobe_font_metrics::{ParseError, parse};
9///
10/// let err = parse("").err();
11///
12/// assert!(matches!(err, Some(ParseError::MissingHeader { line: 1 })));
13/// ```
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum ParseError {
16    /// A byte is outside the supported AFM ASCII text repertoire.
17    InvalidByte {
18        /// Zero-based byte offset in the input.
19        offset: usize,
20        /// One-based source line number.
21        line: usize,
22        /// The rejected byte.
23        value: u8,
24    },
25    /// First non-blank, non-comment line was not `StartFontMetrics`.
26    MissingHeader {
27        /// 1-based source line number where the missing header was expected.
28        line: usize,
29    },
30    /// `StartFontMetrics` declared a version outside the 4.x family.
31    UnsupportedVersion {
32        /// 1-based source line number of the offending `StartFontMetrics`.
33        line: usize,
34        /// Version literal that was rejected (e.g. `"5.0"`).
35        version: String,
36    },
37    /// A required field is missing: `FontName`, `FontBBox`, or `EscChar`
38    /// when `MappingScheme` is 3.
39    MissingRequiredField {
40        /// Name of the missing field.
41        field: &'static str,
42    },
43    /// A token that should have parsed as a number didn't.
44    InvalidNumber {
45        /// 1-based source line number where parsing failed.
46        line: usize,
47        /// Logical field whose value couldn't be parsed (e.g. `"FontBBox"`).
48        field: &'static str,
49        /// The raw token that failed to parse.
50        value: String,
51    },
52    /// A record was structurally malformed (wrong arity, unrecognised
53    /// boolean, etc.).
54    MalformedRecord {
55        /// 1-based source line number where the record appeared.
56        line: usize,
57        /// AFM keyword that introduced the record.
58        keyword: &'static str,
59        /// Human-readable description of how the record was malformed.
60        reason: &'static str,
61    },
62}
63
64impl fmt::Display for ParseError {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        match self {
67            Self::InvalidByte {
68                offset,
69                line,
70                value,
71            } => {
72                write!(
73                    f,
74                    "line {line}: invalid AFM byte {value:#04x} at offset {offset}"
75                )
76            }
77            Self::MissingHeader { line } => {
78                write!(f, "line {line}: expected StartFontMetrics header")
79            }
80            Self::UnsupportedVersion { line, version } => {
81                write!(
82                    f,
83                    "line {line}: unsupported AFM version {version:?} (need 4.x)"
84                )
85            }
86            Self::MissingRequiredField { field } => {
87                write!(f, "missing required field {field}")
88            }
89            Self::InvalidNumber { line, field, value } => {
90                write!(f, "line {line}: invalid number {value:?} for {field}")
91            }
92            Self::MalformedRecord {
93                line,
94                keyword,
95                reason,
96            } => {
97                write!(f, "line {line}: malformed {keyword} record: {reason}")
98            }
99        }
100    }
101}
102
103impl Error for ParseError {}