Skip to main content

rusty_figlet/
error.rs

1//! Library error type for `rusty-figlet`.
2//!
3//! [`FigletError`] is the unified error type returned by every fallible
4//! public API in this crate. It is marked `#[non_exhaustive]` so that
5//! additive variants in future releases remain non-breaking under SemVer
6//! (per AD-013). Downstream consumers that pattern-match on the enum MUST
7//! include a wildcard `_` arm.
8//!
9//! `Send + Sync + 'static` is guaranteed at compile time (SC-009) so the
10//! error works across async `await` points and thread boundaries.
11
12use std::io;
13use std::path::PathBuf;
14
15/// All fallible operations in `rusty-figlet` return `Result<T, FigletError>`.
16///
17/// The enum is `#[non_exhaustive]` (per AD-013) so additive variants in
18/// future minor releases do NOT constitute a breaking change. Downstream
19/// matches MUST include a wildcard `_` arm:
20///
21/// ```rust
22/// use rusty_figlet::FigletError;
23/// fn describe(err: &FigletError) -> &'static str {
24///     match err {
25///         FigletError::FontNotFound { .. } => "missing font",
26///         FigletError::FontParse { .. } => "bad font file",
27///         FigletError::Io(_) => "io error",
28///         FigletError::WidthTooNarrow { .. } => "width too narrow",
29///         FigletError::Internal(_) => "internal error",
30///         _ => "unknown",
31///     }
32/// }
33/// ```
34///
35/// `Error::source()` returns `Some(&io::Error)` ONLY for the [`FigletError::Io`]
36/// variant; all other variants are leaf errors and return `None` from
37/// `source()`. `FontParse { line }` is 1-indexed and matches the convention
38/// used by upstream `figlet(6)` parse-error stderr messages.
39#[non_exhaustive]
40#[derive(Debug, thiserror::Error)]
41pub enum FigletError {
42    /// The requested font name (or path) could not be located.
43    ///
44    /// `name` is the user-supplied identifier; `searched` is the ordered
45    /// list of paths the resolver consulted, suitable for displaying in a
46    /// diagnostic message.
47    #[error("font not found: {name}; searched {searched:?}")]
48    FontNotFound {
49        /// Font name or path the user supplied (e.g. `"slant"`, `"./my.flf"`).
50        name: String,
51        /// Ordered list of paths inspected during font resolution.
52        searched: Vec<PathBuf>,
53    },
54
55    /// A `.flf` file failed to parse.
56    ///
57    /// `reason` is a short human description (e.g. `"bad signature"`,
58    /// `"missing endmark"`); `line` is the 1-indexed line number at which
59    /// the parser detected the problem.
60    #[error("font parse error at line {line}: {reason}")]
61    FontParse {
62        /// Short human-readable description of the parse failure.
63        reason: String,
64        /// 1-indexed line number where the parse error was detected.
65        line: u32,
66    },
67
68    /// Underlying I/O failure (file read, stdin, stdout).
69    ///
70    /// `Error::source()` returns the wrapped [`io::Error`] for this variant.
71    #[error("io error: {0}")]
72    Io(#[from] io::Error),
73
74    /// The requested width is too narrow to render the requested glyph(s).
75    ///
76    /// `needed` is the minimum width a single glyph requires; `given` is
77    /// the width the caller supplied.
78    #[error("width too narrow: needed {needed}, given {given}")]
79    WidthTooNarrow {
80        /// Minimum width required by the widest glyph.
81        needed: u32,
82        /// Width supplied by the caller.
83        given: u32,
84    },
85
86    /// An internal invariant was violated. Indicates a bug in the library;
87    /// please file an issue.
88    #[error("internal error: {0}")]
89    Internal(&'static str),
90}