1
use std::{convert::Infallible, str::Utf8Error, string::FromUtf8Error, sync::Arc};
2

            
3
use bonsaidb_core::{
4
    permissions::PermissionDenied,
5
    pubsub::{Disconnected, TryReceiveError},
6
    schema::{view, InsertError, InvalidNameError},
7
    AnyError,
8
};
9
use nebari::AbortError;
10

            
11
use crate::database::compat::UnknownVersion;
12

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

            
20
    /// An error occurred serializing the underlying database structures.
21
    #[error("error while serializing internal structures: {0}")]
22
    InternalSerialization(String),
23

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

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

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

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

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

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

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

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

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

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

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

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

            
76
    /// An error occurred with a password hash.
77
    #[cfg(feature = "password-hashing")]
78
    #[error("password hash error: {0}")]
79
    PasswordHash(String),
80
}
81

            
82
impl<T> From<InsertError<T>> for Error {
83
    fn from(err: InsertError<T>) -> Self {
84
        Self::Core(err.error)
85
    }
86
}
87

            
88
impl From<flume::RecvError> for Error {
89
    fn from(_: flume::RecvError) -> Self {
90
        Self::InternalCommunication
91
    }
92
}
93

            
94
impl From<TryReceiveError> for Error {
95
    fn from(_: TryReceiveError) -> Self {
96
        Self::InternalCommunication
97
    }
98
}
99

            
100
impl From<Disconnected> for Error {
101
    fn from(_: Disconnected) -> Self {
102
        Self::InternalCommunication
103
    }
104
}
105

            
106
impl From<bincode::Error> for Error {
107
    fn from(err: bincode::Error) -> Self {
108
        Self::InternalSerialization(err.to_string())
109
    }
110
}
111

            
112
impl<T> From<UnknownVersion<T>> for Error {
113
    fn from(err: UnknownVersion<T>) -> Self {
114
        Self::InternalSerialization(err.to_string())
115
    }
116
}
117

            
118
#[cfg(feature = "password-hashing")]
119
impl From<argon2::Error> for Error {
120
    fn from(err: argon2::Error) -> Self {
121
        Self::PasswordHash(err.to_string())
122
    }
123
}
124

            
125
#[cfg(feature = "password-hashing")]
126
impl From<argon2::password_hash::Error> for Error {
127
    fn from(err: argon2::password_hash::Error) -> Self {
128
        Self::PasswordHash(err.to_string())
129
    }
130
}
131

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

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

            
146
impl From<Error> for bonsaidb_core::Error {
147
    fn from(err: Error) -> Self {
148
124
        match err {
149
19313
            Error::View(view::Error::Core(core)) | Error::Core(core) => core,
150
2
            other => Self::Database(other.to_string()),
151
        }
152
19315
    }
153
}
154

            
155
impl From<Arc<Error>> for Error {
156
    fn from(err: Arc<Error>) -> Self {
157
        match Arc::try_unwrap(err) {
158
            Ok(err) => err,
159
            Err(still_wrapped) => Error::Job(still_wrapped),
160
        }
161
    }
162
}
163

            
164
impl From<FromUtf8Error> for Error {
165
    fn from(err: FromUtf8Error) -> Self {
166
        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
167
    }
168
}
169

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

            
176
impl From<InvalidNameError> for Error {
177
    fn from(err: InvalidNameError) -> Self {
178
        Self::Core(bonsaidb_core::Error::from(err))
179
    }
180
}
181

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

            
191
impl From<AbortError<Error>> for Error {
192
1
    fn from(err: AbortError<Error>) -> Self {
193
1
        match err {
194
1
            AbortError::Nebari(error) => Self::Nebari(error),
195
            AbortError::Other(error) => error,
196
        }
197
1
    }
198
}
199

            
200
impl From<PermissionDenied> for Error {
201
2
    fn from(err: PermissionDenied) -> Self {
202
2
        Self::Core(bonsaidb_core::Error::from(err))
203
2
    }
204
}
205

            
206
1
#[test]
207
1
fn test_converting_error() {
208
1
    use serde::ser::Error as _;
209
1
    let err: bonsaidb_core::Error = Error::Serialization(pot::Error::custom("mymessage")).into();
210
1
    match err {
211
1
        bonsaidb_core::Error::Database(storage_error) => {
212
1
            assert!(storage_error.contains("mymessage"));
213
        }
214
        _ => unreachable!(),
215
    }
216
1
}