pith_digest/error.rs
1//! The one error type every fallible operation in the kit returns.
2
3use core::fmt;
4
5/// The single error type of the `pith` suite.
6///
7/// Every fallible operation across the workspace returns
8/// [`Result<T>`](crate::Result), which uses this type, so a caller that
9/// handles errors once handles all of them. Each variant carries a
10/// `&'static str` naming the field or structure at fault, so a message
11/// names a thing rather than saying "invalid input".
12///
13/// [`Display`](core::fmt::Display) never allocates and never runs the
14/// formatting machinery: it concatenates the literal prefix with the
15/// `what` field through [`Formatter::write_str`](core::fmt::Formatter::write_str)
16/// alone. The numeric payloads (`needed`, `found`, `limit`) stay
17/// reachable through `Debug`, which derives normally.
18#[derive(Copy, Clone, Debug, PartialEq, Eq)]
19pub enum Error {
20 /// Input ended before a structure that the format guarantees.
21 Truncated {
22 /// What was being read, e.g. `"idat chunk"`.
23 what: &'static str,
24 /// How many bytes the structure needs.
25 needed: usize,
26 /// How many bytes were actually there.
27 found: usize,
28 },
29 /// A magic number, signature or fixed field did not match.
30 InvalidMagic {
31 /// The field that did not match, e.g. `"PNG signature"`.
32 what: &'static str,
33 },
34 /// A structurally valid but semantically impossible value: a zero
35 /// denominator, a declared length that cannot fit, a table index past
36 /// the end of the table.
37 BadValue(&'static str),
38 /// A real format variant this crate deliberately does not implement.
39 /// This is not a failure to parse; it is a refusal to guess.
40 Unsupported(&'static str),
41 /// An allocation the format could request but that exceeds a
42 /// configured ceiling. Always a refusal, never an OOM.
43 TooLarge {
44 /// The thing whose size exceeded the ceiling.
45 what: &'static str,
46 /// The configured ceiling, in bytes.
47 limit: usize,
48 },
49}
50
51impl Error {
52 /// Builds [`Error::Truncated`] without spelling the struct literal.
53 pub fn truncated(what: &'static str, needed: usize, found: usize) -> Self {
54 Self::Truncated {
55 what,
56 needed,
57 found,
58 }
59 }
60
61 /// Builds [`Error::TooLarge`] without spelling the struct literal.
62 pub fn too_large(what: &'static str, limit: usize) -> Self {
63 Self::TooLarge { what, limit }
64 }
65}
66
67impl fmt::Display for Error {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 Error::Truncated { what, .. } => {
71 f.write_str("truncated: ")?;
72 f.write_str(what)
73 }
74 Error::InvalidMagic { what } => {
75 f.write_str("invalid magic: ")?;
76 f.write_str(what)
77 }
78 Error::BadValue(what) => {
79 f.write_str("bad value: ")?;
80 f.write_str(what)
81 }
82 Error::Unsupported(what) => {
83 f.write_str("unsupported: ")?;
84 f.write_str(what)
85 }
86 Error::TooLarge { what, .. } => {
87 f.write_str("too large: ")?;
88 f.write_str(what)
89 }
90 }
91 }
92}
93
94/// The result type used by every fallible operation in the kit. The
95/// error type defaults to [`Error`], which is what the kit's own APIs
96/// return; the parameter stays open so host code can reuse the alias
97/// with its own error type.
98pub type Result<T, E = Error> = core::result::Result<T, E>;