Skip to main content

zbus_lockstep/
error.rs

1use std::path::PathBuf;
2
3#[non_exhaustive]
4#[derive(Debug)]
5pub enum LockstepError {
6    ArgumentNotFound(String),
7    InterfaceNotFound(String),
8    MemberNotFound(String),
9    PropertyNotFound(String),
10    PathNotFound(PathBuf),
11    Env(std::env::VarError),
12    Fmt(std::fmt::Error),
13    Io(std::io::Error),
14    Xml(zbus_xml::Error),
15    Zvariant(zvariant::Error),
16}
17
18impl std::error::Error for LockstepError {
19    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
20        match self {
21            LockstepError::Env(e) => Some(e),
22            LockstepError::Fmt(e) => Some(e),
23            LockstepError::Io(e) => Some(e),
24            LockstepError::Xml(e) => Some(e),
25            LockstepError::Zvariant(e) => Some(e),
26            _ => None,
27        }
28    }
29}
30
31impl std::fmt::Display for LockstepError {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            LockstepError::ArgumentNotFound(name) => write!(f, "Argument \"{name}\" not found."),
35            LockstepError::InterfaceNotFound(name) => write!(f, "Interface \"{name}\" not found."),
36            LockstepError::MemberNotFound(name) => write!(f, "Member \"{name}\" not found."),
37            LockstepError::PropertyNotFound(name) => write!(f, "Property \"{name}\" not found."),
38            LockstepError::PathNotFound(path) => write!(
39                f,
40                "No XML path provided and default XML path not found. Searched directory: \"{}\"",
41                path.display()
42            ),
43            LockstepError::Env(e) => write!(f, "Environment variable error: {e}"),
44            LockstepError::Fmt(e) => write!(f, "Formatting error: {e}"),
45            LockstepError::Io(e) => write!(f, "IO error: {e}"),
46            LockstepError::Xml(e) => write!(f, "XML error: {e}"),
47            LockstepError::Zvariant(e) => write!(f, "Zvariant signature error: {e}"),
48        }
49    }
50}
51
52impl From<std::io::Error> for LockstepError {
53    fn from(e: std::io::Error) -> Self {
54        LockstepError::Io(e)
55    }
56}
57
58impl From<zbus_xml::Error> for LockstepError {
59    fn from(e: zbus_xml::Error) -> Self {
60        LockstepError::Xml(e)
61    }
62}
63
64impl From<zvariant::Error> for LockstepError {
65    fn from(e: zvariant::Error) -> Self {
66        LockstepError::Zvariant(e)
67    }
68}
69
70impl From<zvariant::signature::Error> for LockstepError {
71    fn from(e: zvariant::signature::Error) -> Self {
72        // Under-the-hood `zvariant` converts this to `zvariant::Error::SignatureParse(e)`
73        LockstepError::Zvariant(zvariant::Error::from(e))
74    }
75}
76
77impl From<std::env::VarError> for LockstepError {
78    fn from(e: std::env::VarError) -> Self {
79        LockstepError::Env(e)
80    }
81}
82
83impl From<std::fmt::Error> for LockstepError {
84    fn from(e: std::fmt::Error) -> Self {
85        LockstepError::Fmt(e)
86    }
87}
88
89// `LockstepError` wraps upstream errors (e.g. `io::Error`) that are `!UnwindSafe`
90// because they may carry a `Box<dyn Error>`, which the compiler conservatively
91// assumes could hide interior mutability. This propagates and strips the auto
92// traits from `LockstepError`.
93//
94// These impls are sound: `LockstepError` is passive, owned error data with no
95// interior mutability (`Cell`/`RefCell`) and no handles to shared mutable state.
96// It is only ever read (e.g. via `Display`), never mutated, so a panic can never
97// leave it holding a broken invariant that could be observed across a
98// `catch_unwind` boundary.
99impl std::panic::UnwindSafe for LockstepError {}
100impl std::panic::RefUnwindSafe for LockstepError {}