Skip to main content

rahti_native/
error.rs

1//! What a native host is told when startup cannot continue.
2//!
3//! Every failure in this crate is a value, never an exit. A packaged
4//! application has no terminal: a process that calls `std::process::exit`
5//! during startup is, from the user's side, a program that did not open. The
6//! host is expected to show [`NativeError`] in a dialog and stop, which is the
7//! difference between "the database could not be created" and nothing at all.
8
9use std::fmt;
10use std::path::{Path, PathBuf};
11
12/// A native startup or packaging failure.
13///
14/// `step` names the part of startup that failed so a host can say *where*
15/// without parsing the message, and `Display` is the sentence to show.
16#[derive(Debug)]
17pub struct NativeError {
18    /// Which part of startup failed: `"paths"`, `"listener"`, `"secret"`,
19    /// `"assets"`, `"config"`, `"server"`.
20    pub step: &'static str,
21    /// The failure, phrased for a person.
22    pub message: String,
23    /// The path involved, when there was one.
24    pub path: Option<PathBuf>,
25}
26
27impl NativeError {
28    pub fn new(step: &'static str, message: impl Into<String>) -> Self {
29        NativeError {
30            step,
31            message: message.into(),
32            path: None,
33        }
34    }
35
36    pub fn at(step: &'static str, path: impl AsRef<Path>, message: impl Into<String>) -> Self {
37        NativeError {
38            step,
39            message: message.into(),
40            path: Some(path.as_ref().to_path_buf()),
41        }
42    }
43
44    /// An `io::Error` with the path it happened to, which the standard error
45    /// does not carry and which is the only part a user can act on.
46    pub fn io(step: &'static str, path: impl AsRef<Path>, error: std::io::Error) -> Self {
47        NativeError::at(step, path, error.to_string())
48    }
49}
50
51impl fmt::Display for NativeError {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match &self.path {
54            Some(path) => write!(f, "{} ({})", self.message, path.display()),
55            None => write!(f, "{}", self.message),
56        }
57    }
58}
59
60impl std::error::Error for NativeError {}