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 {}