Skip to main content

write_fonts/
error.rs

1//! Errors that occur during writing
2
3use std::sync::Arc;
4
5use types::Tag;
6
7use crate::{graph::Graph, validate::ValidationReport};
8
9/// An error returned when attempting to add a table to the builder.
10///
11/// This wraps a compilation error, adding the tag of the table where it was
12/// encountered.
13#[derive(Clone, Debug)]
14#[non_exhaustive]
15pub struct BuilderError {
16    /// The tag of the root table where the error occurred
17    pub tag: Tag,
18    /// The underlying error
19    pub inner: Error,
20}
21
22/// A packing could not be found that satisfied all offsets
23///
24/// If the "dot2" feature is enabled, you can use the `write_graph_viz` method
25/// on this error to dump a text representation of the graph to disk. You can
26/// then use graphviz to convert this into an image. For example, to create
27/// an SVG, you might use, `dot -v -Tsvg failure.dot2 > failure.svg`, where
28/// 'failure.dot2' is the path where you dumped the graph.
29#[derive(Clone)]
30pub struct PackingError {
31    // this is Arc so that we can clone and still be sent between threads.
32    pub(crate) graph: Arc<Graph>,
33}
34
35/// An error occurred while writing this table
36#[derive(Debug, Clone)]
37pub enum Error {
38    /// The table failed a validation check
39    ///
40    /// This indicates that the table contained invalid or inconsistent data
41    /// (for instance, it had an explicit version set, but contained fields
42    /// not present in that version).
43    ValidationFailed(ValidationReport),
44    /// The table contained overflowing offsets
45    ///
46    /// This indicates that an ordering could not be found that allowed all
47    /// tables to be reachable from their parents. See [`PackingError`] for
48    /// more details.
49    PackingFailed(PackingError),
50    /// Invalid input provided to a builder
51    InvalidInput(&'static str),
52}
53
54impl PackingError {
55    /// Write a graphviz file representing the failed packing to the provided path.
56    ///
57    /// Has the same semantics as [`std::fs::write`].
58    #[cfg(feature = "dot2")]
59    pub fn write_graph_viz(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
60        self.graph.write_graph_viz(path)
61    }
62}
63
64impl std::fmt::Display for BuilderError {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        write!(f, "failed to build '{}' table: '{}'", self.tag, self.inner)
67    }
68}
69
70impl std::error::Error for BuilderError {
71    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
72        Some(&self.inner)
73    }
74}
75
76impl std::fmt::Display for Error {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        match self {
79            Error::ValidationFailed(report) => report.fmt(f),
80            Error::PackingFailed(error) => error.fmt(f),
81            Error::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
82        }
83    }
84}
85
86impl std::fmt::Display for PackingError {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        write!(
89            f,
90            "Table packing failed with {} overflows",
91            self.graph.find_overflows().len()
92        )
93    }
94}
95
96impl std::fmt::Debug for PackingError {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        write!(f, "{self}")
99    }
100}
101
102impl std::error::Error for PackingError {}
103impl std::error::Error for Error {}
104
105impl From<ValidationReport> for Error {
106    fn from(value: ValidationReport) -> Self {
107        Error::ValidationFailed(value)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    /// Some users, notably fontmake-rs, like Send errors.
116    #[test]
117    fn assert_compiler_error_is_send() {
118        fn send_me_baby<T: Send>() {}
119        send_me_baby::<Error>();
120    }
121}