Skip to main content

write_fonts/
error.rs

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