Skip to main content

confex_core/
error.rs

1use std::{fmt, path::PathBuf};
2
3#[derive(Debug)]
4pub enum SourceError {
5    Io {
6        path: PathBuf,
7        source: std::io::Error,
8    },
9    Parse {
10        path: PathBuf,
11        message: String,
12    },
13    Serialize(String),
14    Env(String),
15    Crypto(CryptoError),
16    Backend(String),
17    #[cfg(feature = "redb-backend")]
18    Redb(redb::Error),
19}
20
21impl fmt::Display for SourceError {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Self::Io { path, source } => {
25                write!(f, "I/O error reading {}: {source}", path.display())
26            }
27            Self::Parse { path, message } => {
28                write!(f, "parse error in {}: {message}", path.display())
29            }
30            Self::Serialize(msg) => write!(f, "serialization error: {msg}"),
31            Self::Env(msg) => write!(f, "environment variable error: {msg}"),
32            Self::Crypto(e) => write!(f, "crypto error: {e}"),
33            Self::Backend(msg) => write!(f, "backend error: {msg}"),
34            #[cfg(feature = "redb-backend")]
35            Self::Redb(e) => write!(f, "redb error: {e}"),
36        }
37    }
38}
39
40impl std::error::Error for SourceError {
41    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
42        match self {
43            Self::Io { source, .. } => Some(source),
44            Self::Crypto(e) => Some(e),
45            #[cfg(feature = "redb-backend")]
46            Self::Redb(e) => Some(e),
47            _ => None,
48        }
49    }
50}
51
52impl From<CryptoError> for SourceError {
53    fn from(e: CryptoError) -> Self {
54        Self::Crypto(e)
55    }
56}
57
58#[cfg(feature = "redb-backend")]
59mod redb_err {
60    use super::SourceError;
61
62    impl From<redb::Error> for SourceError {
63        fn from(e: redb::Error) -> Self {
64            Self::Redb(e)
65        }
66    }
67    impl From<redb::DatabaseError> for SourceError {
68        fn from(e: redb::DatabaseError) -> Self {
69            Self::Redb(e.into())
70        }
71    }
72    impl From<redb::TransactionError> for SourceError {
73        fn from(e: redb::TransactionError) -> Self {
74            Self::Redb(e.into())
75        }
76    }
77    impl From<redb::TableError> for SourceError {
78        fn from(e: redb::TableError) -> Self {
79            Self::Redb(e.into())
80        }
81    }
82    impl From<redb::StorageError> for SourceError {
83        fn from(e: redb::StorageError) -> Self {
84            Self::Redb(e.into())
85        }
86    }
87    impl From<redb::CommitError> for SourceError {
88        fn from(e: redb::CommitError) -> Self {
89            Self::Redb(e.into())
90        }
91    }
92}
93
94#[derive(Debug)]
95pub enum LoadError {
96    Source(SourceError),
97    Migration(MigrationError),
98    Crypto(CryptoError),
99    Deserialize(crate::deserialize::DeserializeError),
100}
101
102impl fmt::Display for LoadError {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        match self {
105            Self::Source(e) => fmt::Display::fmt(e, f),
106            Self::Migration(e) => fmt::Display::fmt(e, f),
107            Self::Crypto(e) => fmt::Display::fmt(e, f),
108            Self::Deserialize(e) => write!(f, "deserialization failed: {e}"),
109        }
110    }
111}
112
113impl std::error::Error for LoadError {
114    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
115        match self {
116            Self::Source(e) => Some(e),
117            Self::Migration(e) => Some(e),
118            Self::Crypto(e) => Some(e),
119            Self::Deserialize(e) => Some(e),
120        }
121    }
122}
123
124impl From<SourceError> for LoadError {
125    fn from(e: SourceError) -> Self {
126        Self::Source(e)
127    }
128}
129
130impl From<MigrationError> for LoadError {
131    fn from(e: MigrationError) -> Self {
132        Self::Migration(e)
133    }
134}
135
136impl From<CryptoError> for LoadError {
137    fn from(e: CryptoError) -> Self {
138        Self::Crypto(e)
139    }
140}
141
142impl From<crate::deserialize::DeserializeError> for LoadError {
143    fn from(e: crate::deserialize::DeserializeError) -> Self {
144        Self::Deserialize(e)
145    }
146}
147
148#[derive(Debug)]
149pub enum MigrationError {
150    NoPath { from: u32, to: u32 },
151    Step(String),
152}
153
154impl fmt::Display for MigrationError {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        match self {
157            Self::NoPath { from, to } => {
158                write!(f, "no migration path from version {from} to {to}")
159            }
160            Self::Step(msg) => write!(f, "migration step failed: {msg}"),
161        }
162    }
163}
164
165impl std::error::Error for MigrationError {}
166
167#[derive(Debug)]
168pub enum KeyError {
169    Io(std::io::Error),
170    InvalidLength(usize),
171    /// No Secret Service daemon available (headless or server environment).
172    #[cfg(all(target_os = "linux", feature = "native-keyring"))]
173    NoDaemon,
174    #[cfg(all(target_os = "linux", feature = "native-keyring"))]
175    SecretService(String),
176    #[cfg(all(target_os = "macos", feature = "native-keyring"))]
177    Keychain(security_framework::base::Error),
178    #[cfg(all(windows, feature = "native-keyring"))]
179    CredentialManager(String),
180    #[cfg(feature = "sealed-key")]
181    Kdf(argon2::Error),
182    InvalidBlob,
183    Passphrase,
184}
185
186impl fmt::Display for KeyError {
187    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188        match self {
189            Self::Io(e) => write!(f, "I/O error: {e}"),
190            Self::InvalidLength(n) => {
191                write!(f, "invalid key length: expected 32 bytes, got {n}")
192            }
193            #[cfg(all(target_os = "linux", feature = "native-keyring"))]
194            Self::NoDaemon => write!(f, "Secret Service daemon not available"),
195            #[cfg(all(target_os = "linux", feature = "native-keyring"))]
196            Self::SecretService(e) => write!(f, "Secret Service error: {e}"),
197            #[cfg(all(target_os = "macos", feature = "native-keyring"))]
198            Self::Keychain(e) => write!(f, "keychain error: {e}"),
199            #[cfg(all(windows, feature = "native-keyring"))]
200            Self::CredentialManager(msg) => write!(f, "Credential Manager error: {msg}"),
201            #[cfg(feature = "sealed-key")]
202            Self::Kdf(e) => write!(f, "KDF error: {e}"),
203            Self::InvalidBlob => write!(f, "sealed key blob is invalid"),
204            Self::Passphrase => write!(f, "passphrase not available"),
205        }
206    }
207}
208
209impl std::error::Error for KeyError {
210    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
211        match self {
212            Self::Io(e) => Some(e),
213            #[cfg(all(target_os = "linux", feature = "native-keyring"))]
214            Self::NoDaemon | Self::SecretService(_) => None,
215            #[cfg(all(target_os = "macos", feature = "native-keyring"))]
216            Self::Keychain(e) => Some(e),
217            _ => None,
218        }
219    }
220}
221
222impl From<std::io::Error> for KeyError {
223    fn from(e: std::io::Error) -> Self {
224        Self::Io(e)
225    }
226}
227
228#[cfg(all(target_os = "macos", feature = "native-keyring"))]
229impl From<security_framework::base::Error> for KeyError {
230    fn from(e: security_framework::base::Error) -> Self {
231        Self::Keychain(e)
232    }
233}
234
235#[cfg(feature = "sealed-key")]
236impl From<argon2::Error> for KeyError {
237    fn from(e: argon2::Error) -> Self {
238        Self::Kdf(e)
239    }
240}
241
242#[derive(Debug)]
243pub enum CryptoError {
244    Encrypt,
245    Decrypt,
246    InvalidFormat,
247    NotAString(String),
248}
249
250impl fmt::Display for CryptoError {
251    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252        match self {
253            Self::Encrypt => write!(f, "encryption failed"),
254            Self::Decrypt => write!(f, "decryption failed"),
255            Self::InvalidFormat => write!(f, "invalid ciphertext format"),
256            Self::NotAString(field) => write!(f, "value at field '{field}' is not a string"),
257        }
258    }
259}
260
261impl std::error::Error for CryptoError {}