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}