tididi_cnf/error.rs
1//! The one error type the library returns and the `tididi` binary reports.
2
3/// Everything that stops a run before it has an answer.
4///
5/// The variant is the failure class, which fixes the status the binary exits
6/// with and the name the run record gives it ([`Error::kind`]). The string
7/// says what went wrong, in words an operator can act on;
8/// [`Display`](std::fmt::Display) prints it, and the binary prints it on
9/// stderr after `error: `.
10#[derive(Debug)]
11pub enum Error {
12 /// An option is contradictory, or inert in the mode this run resolved to.
13 Usage(String),
14 /// An environment setting is invalid, or is set where this run would
15 /// ignore it.
16 Environment(String),
17 /// A preprocessing frontend or a compile stage failed.
18 Stage(String),
19 /// The requested vtree spec cannot serve this run.
20 VtreeSpec(String),
21 /// The input could not be opened or read, or does not describe a formula.
22 Input(String),
23 /// An artifact the run was asked to write could not be produced.
24 Artifact(String),
25 /// The run ended without a count: it reached its time limit, or every
26 /// compile and recovery path gave up. The stage that gave up says on
27 /// stderr what stopped it; the message says which of these ended the run.
28 Incomplete(String),
29}
30
31impl Error {
32 /// An allocation was refused and the run has no count to print.
33 pub(crate) fn out_of_memory() -> Self {
34 Error::Incomplete(OUT_OF_MEMORY.to_string())
35 }
36
37 /// The compile, and every path behind it, gave up without a count.
38 pub(crate) fn compile_gave_up() -> Self {
39 Error::Incomplete("no answer: the compile gave up".to_owned())
40 }
41
42 /// Every stage of a projected count declined or gave up.
43 pub(crate) fn every_stage_gave_up() -> Self {
44 Error::Incomplete("no answer: every stage gave up".to_owned())
45 }
46
47 /// `map_err` adapter for a failed preprocessing or expansion stage:
48 /// `{what} failed: {error}`.
49 pub(crate) fn stage_failed<E: std::fmt::Display>(what: &'static str) -> impl FnOnce(E) -> Self {
50 move |error| Error::Stage(format!("{what} failed: {error}"))
51 }
52
53 /// The class's name, as the run record's `exit_reason` gives it: `usage`,
54 /// `environment`, `stage`, `vtree-spec`, `input`, `artifact` or
55 /// `incomplete`.
56 pub fn kind(&self) -> &'static str {
57 match self {
58 Error::Usage(_) => "usage",
59 Error::Environment(_) => "environment",
60 Error::Stage(_) => "stage",
61 Error::VtreeSpec(_) => "vtree-spec",
62 Error::Input(_) => "input",
63 Error::Artifact(_) => "artifact",
64 Error::Incomplete(_) => "incomplete",
65 }
66 }
67
68 /// The status the binary exits with for this class.
69 pub(crate) fn exit_code(&self) -> u8 {
70 match self {
71 Error::Usage(_) | Error::Environment(_) | Error::Stage(_) => 2,
72 Error::VtreeSpec(_)
73 | Error::Input(_)
74 | Error::Artifact(_)
75 | Error::Incomplete(_) => 1,
76 }
77 }
78}
79
80impl std::fmt::Display for Error {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 let message = match self {
83 Error::Usage(message)
84 | Error::Environment(message)
85 | Error::Stage(message)
86 | Error::VtreeSpec(message)
87 | Error::Input(message)
88 | Error::Artifact(message)
89 | Error::Incomplete(message) => message,
90 };
91 f.write_str(message)
92 }
93}
94
95impl std::error::Error for Error {}
96
97/// Stderr diagnostic for a run an allocation refusal ended.
98///
99/// A benchmark harness reads a process as out of memory by finding
100/// `"memory allocation of"` and `"bytes failed"` in its stderr, which is what
101/// the allocator prints when it aborts. A compile that refuses gracefully never
102/// reaches the allocator's own message, so it says the same thing here and the
103/// run is attributed the same way.
104///
105/// The compile raises it when reducing the finished diagram is refused an
106/// allocation (`compile::GiveUp::OutOfMemory`).
107const OUT_OF_MEMORY: &str = "memory allocation of unknown bytes failed while reducing \
108 the compiled diagram: the run reached its memory limit or the system ran out of \
109 memory, and has no answer. A larger memory limit gives it more room.";
110
111#[cfg(test)]
112#[path = "tests/error.rs"]
113mod tests;