1//! What can go wrong, in the vocabulary of what was being done. No port returns a bare string as
2//! its error: a caller must be able to decide (refuse, retry, fall back) from the type alone.
3
4use std::fmt;
5
6use serde::{Deserialize, Serialize};
7
8/// A holder of Whiskers' documents could not do its job. Which file, which table or which request
9/// failed is the adapter's to log; the caller only needs to know whether to try again or to give up.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum StoreError {
12    /// The storage could not be reached or written. Trying again may work.
13    Unavailable,
14    /// What is stored does not read back as the document it should be. Trying again will not help;
15    /// a person has to look.
16    Damaged,
17}
18
19impl fmt::Display for StoreError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self {
22            StoreError::Unavailable => write!(f, "storage unavailable"),
23            StoreError::Damaged => write!(f, "stored document damaged"),
24        }
25    }
26}
27
28impl std::error::Error for StoreError {}
29
30/// What the other side said about a failure, already phrased for a person (and for the tablet's
31/// log): the status line, the vendor's complaint. Carried so it can be shown and logged. It is never
32/// branched on: anything a caller must decide from is a variant or a field of the error that holds it.
33#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
34pub struct Diagnostic(String);
35
36impl Diagnostic {
37    pub fn new(said: impl Into<String>) -> Self {
38        Self(said.into())
39    }
40
41    pub fn as_str(&self) -> &str {
42        &self.0
43    }
44}
45
46impl fmt::Display for Diagnostic {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        f.write_str(&self.0)
49    }
50}