1
use std::convert::Infallible;
2
use std::fmt::Display;
3
use std::str::Utf8Error;
4
use std::string::FromUtf8Error;
5
use std::sync::Arc;
6

            
7
use bonsaidb_core::permissions::PermissionDenied;
8
use bonsaidb_core::pubsub::{Disconnected, TryReceiveError};
9
use bonsaidb_core::schema::{view, InsertError, InvalidNameError};
10
use bonsaidb_core::AnyError;
11
use nebari::AbortError;
12

            
13
use crate::database::compat::UnknownVersion;
14

            
15
/// Errors that can occur from interacting with storage.
16
3
#[derive(thiserror::Error, Debug)]
17
pub enum Error {
18
    /// An error occurred interacting with the storage layer, `nebari`.
19
    #[error("error from storage: {0}")]
20
    Nebari(#[from] nebari::Error),
21

            
22
    /// An error occurred serializing the contents of a `Document` or results of a `View`.
23
    #[error("error while serializing: {0}")]
24
    Serialization(#[from] pot::Error),
25

            
26
    /// An internal error occurred while waiting for or sending a message.
27
    #[error("error while communicating internally")]
28
    InternalCommunication,
29

            
30
    /// A transaction was too large to execute.
31
    #[error("transaction is too large")]
32
    TransactionTooLarge,
33

            
34
    /// An error occurred while executing a view
35
    #[error("error from view: {0}")]
36
    View(#[from] view::Error),
37

            
38
    /// An error occurred in the secrets storage layer.
39
    #[error("a vault error occurred: {0}")]
40
    #[cfg(feature = "encryption")]
41
    Vault(#[from] crate::vault::Error),
42

            
43
    /// An error occurred decompressing a stored value.
44
    #[error("a vault error occurred: {0}")]
45
    #[cfg(feature = "compression")]
46
    Compression(#[from] lz4_flex::block::DecompressError),
47

            
48
    /// A collection requested to be encrypted, but encryption is disabled.
49
    #[error("encryption is disabled, but a collection is requesting encryption")]
50
    #[cfg(not(feature = "encryption"))]
51
    EncryptionDisabled,
52

            
53
    /// An core error occurred.
54
    #[error("a core error occurred: {0}")]
55
    Core(#[from] bonsaidb_core::Error),
56

            
57
    /// A tokio task failed to execute.
58
    #[cfg(feature = "async")]
59
    #[error("a concurrency error ocurred: {0}")]
60
    TaskJoin(#[from] tokio::task::JoinError),
61

            
62
    /// An io error occurred.
63
    #[error("an IO error occurred: {0}")]
64
    Io(#[from] std::io::Error),
65

            
66
    /// An error occurred from a job and couldn't be unwrapped due to clones.
67
    #[error("an error from a job occurred: {0}")]
68
    Job(Arc<Error>),
69

            
70
    /// An error occurred from backing up or restoring.
71
    #[error("a backup error: {0}")]
72
    Backup(Box<dyn AnyError>),
73

            
74
    /// An error occurred with a password hash.
75
    #[cfg(all(feature = "password-hashing", feature = "cli"))]
76
    #[error("error reading password: {0}")]
77
    CommandLinePassword(#[from] crate::cli::ReadPasswordError),
78
}
79

            
80
impl Error {
81
    pub(crate) fn other(origin: impl Display, error: impl Display) -> Self {
82
        Self::Core(bonsaidb_core::Error::other(origin, error))
83
    }
84
}
85

            
86
impl<T> From<InsertError<T>> for Error {
87
    fn from(err: InsertError<T>) -> Self {
88
        Self::Core(err.error)
89
    }
90
}
91

            
92
impl From<flume::RecvError> for Error {
93
    fn from(_: flume::RecvError) -> Self {
94
        Self::InternalCommunication
95
    }
96
}
97

            
98
impl From<TryReceiveError> for Error {
99
    fn from(_: TryReceiveError) -> Self {
100
        Self::InternalCommunication
101
    }
102
}
103

            
104
impl From<Disconnected> for Error {
105
    fn from(_: Disconnected) -> Self {
106
        Self::InternalCommunication
107
    }
108
}
109

            
110
impl From<bincode::Error> for Error {
111
    fn from(err: bincode::Error) -> Self {
112
        Self::other("bincode", err)
113
    }
114
}
115

            
116
impl<T> From<UnknownVersion<T>> for Error {
117
    fn from(err: UnknownVersion<T>) -> Self {
118
        Self::other("unknown versiion", err)
119
    }
120
}
121

            
122
#[cfg(feature = "password-hashing")]
123
impl From<argon2::Error> for Error {
124
    fn from(err: argon2::Error) -> Self {
125
        Self::other("argon2", err)
126
    }
127
}
128

            
129
#[cfg(feature = "password-hashing")]
130
impl From<argon2::password_hash::Error> for Error {
131
    fn from(err: argon2::password_hash::Error) -> Self {
132
        Self::other("argon2", err)
133
    }
134
}
135

            
136
#[cfg(feature = "async")]
137
impl From<tokio::sync::oneshot::error::RecvError> for Error {
138
    fn from(_: tokio::sync::oneshot::error::RecvError) -> Self {
139
        Self::InternalCommunication
140
    }
141
}
142

            
143
#[cfg(feature = "async")]
144
impl From<tokio::sync::oneshot::error::TryRecvError> for Error {
145
    fn from(_: tokio::sync::oneshot::error::TryRecvError) -> Self {
146
        Self::InternalCommunication
147
    }
148
}
149

            
150
impl From<Error> for bonsaidb_core::Error {
151
    fn from(err: Error) -> Self {
152
152
        match err {
153
25137
            Error::View(view::Error::Core(core)) | Error::Core(core) => core,
154
2
            other => Self::other("bonsaidb-local", other),
155
        }
156
25139
    }
157
}
158

            
159
impl From<Arc<Error>> for Error {
160
    fn from(err: Arc<Error>) -> Self {
161
        match Arc::try_unwrap(err) {
162
            Ok(err) => err,
163
            Err(still_wrapped) => Error::Job(still_wrapped),
164
        }
165
    }
166
}
167

            
168
impl From<FromUtf8Error> for Error {
169
    fn from(err: FromUtf8Error) -> Self {
170
        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
171
    }
172
}
173

            
174
impl From<Utf8Error> for Error {
175
    fn from(err: Utf8Error) -> Self {
176
        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
177
    }
178
}
179

            
180
impl From<InvalidNameError> for Error {
181
    fn from(err: InvalidNameError) -> Self {
182
        Self::Core(bonsaidb_core::Error::from(err))
183
    }
184
}
185

            
186
impl From<AbortError<Infallible>> for Error {
187
    fn from(err: AbortError<Infallible>) -> Self {
188
        match err {
189
            AbortError::Nebari(error) => Self::Nebari(error),
190
            AbortError::Other(_) => unreachable!(),
191
        }
192
    }
193
}
194

            
195
impl From<AbortError<Error>> for Error {
196
37
    fn from(err: AbortError<Error>) -> Self {
197
37
        match err {
198
37
            AbortError::Nebari(error) => Self::Nebari(error),
199
            AbortError::Other(error) => error,
200
        }
201
37
    }
202
}
203

            
204
impl From<PermissionDenied> for Error {
205
2
    fn from(err: PermissionDenied) -> Self {
206
2
        Self::Core(bonsaidb_core::Error::from(err))
207
2
    }
208
}
209

            
210
1
#[test]
211
1
fn test_converting_error() {
212
1
    use serde::ser::Error as _;
213
1
    let err: bonsaidb_core::Error = Error::Serialization(pot::Error::custom("mymessage")).into();
214
1
    match err {
215
1
        bonsaidb_core::Error::Other { error, .. } => {
216
1
            assert!(error.contains("mymessage"));
217
        }
218
        _ => unreachable!(),
219
    }
220
1
}