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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
62
    /// A tokio task failed to execute.
63
    #[error("an IO error occurred: {0}")]
64
    Io(#[from] tokio::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(feature = "password-hashing")]
76
    #[error("password hash error: {0}")]
77
    PasswordHash(String),
78
}
79

            
80
impl From<flume::RecvError> for Error {
81
    fn from(_: flume::RecvError) -> Self {
82
        Self::InternalCommunication
83
    }
84
}
85

            
86
impl From<bincode::Error> for Error {
87
    fn from(err: bincode::Error) -> Self {
88
        Self::InternalSerialization(err.to_string())
89
    }
90
}
91

            
92
impl<T> From<UnknownVersion<T>> for Error {
93
    fn from(err: UnknownVersion<T>) -> Self {
94
        Self::InternalSerialization(err.to_string())
95
    }
96
}
97

            
98
#[cfg(feature = "password-hashing")]
99
impl From<argon2::Error> for Error {
100
    fn from(err: argon2::Error) -> Self {
101
        Self::PasswordHash(err.to_string())
102
    }
103
}
104

            
105
#[cfg(feature = "password-hashing")]
106
impl From<argon2::password_hash::Error> for Error {
107
    fn from(err: argon2::password_hash::Error) -> Self {
108
        Self::PasswordHash(err.to_string())
109
    }
110
}
111

            
112
impl From<tokio::sync::oneshot::error::RecvError> for Error {
113
    fn from(_: tokio::sync::oneshot::error::RecvError) -> Self {
114
        Self::InternalCommunication
115
    }
116
}
117

            
118
impl From<tokio::sync::oneshot::error::TryRecvError> for Error {
119
    fn from(_: tokio::sync::oneshot::error::TryRecvError) -> Self {
120
        Self::InternalCommunication
121
    }
122
}
123

            
124
impl From<Error> for bonsaidb_core::Error {
125
    fn from(err: Error) -> Self {
126
80
        match err {
127
16211
            Error::View(view::Error::Core(core)) | Error::Core(core) => core,
128
2
            other => Self::Database(other.to_string()),
129
        }
130
16213
    }
131
}
132

            
133
impl From<Arc<Error>> for Error {
134
    fn from(err: Arc<Error>) -> Self {
135
        match Arc::try_unwrap(err) {
136
            Ok(err) => err,
137
            Err(still_wrapped) => Error::Job(still_wrapped),
138
        }
139
    }
140
}
141

            
142
impl From<FromUtf8Error> for Error {
143
    fn from(err: FromUtf8Error) -> Self {
144
        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
145
    }
146
}
147

            
148
impl From<Utf8Error> for Error {
149
    fn from(err: Utf8Error) -> Self {
150
        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
151
    }
152
}
153

            
154
impl From<InvalidNameError> for Error {
155
    fn from(err: InvalidNameError) -> Self {
156
        Self::Core(bonsaidb_core::Error::from(err))
157
    }
158
}
159

            
160
impl From<AbortError<Infallible>> for Error {
161
    fn from(err: AbortError<Infallible>) -> Self {
162
        match err {
163
            AbortError::Nebari(error) => Self::Nebari(error),
164
            AbortError::Other(_) => unreachable!(),
165
        }
166
    }
167
}
168

            
169
impl From<AbortError<Error>> for Error {
170
26
    fn from(err: AbortError<Error>) -> Self {
171
26
        match err {
172
26
            AbortError::Nebari(error) => Self::Nebari(error),
173
            AbortError::Other(error) => error,
174
        }
175
26
    }
176
}
177

            
178
impl From<PermissionDenied> for Error {
179
2
    fn from(err: PermissionDenied) -> Self {
180
2
        Self::Core(bonsaidb_core::Error::from(err))
181
2
    }
182
}
183

            
184
1
#[test]
185
1
fn test_converting_error() {
186
1
    use serde::ser::Error as _;
187
1
    let err: bonsaidb_core::Error = Error::Serialization(pot::Error::custom("mymessage")).into();
188
1
    match err {
189
1
        bonsaidb_core::Error::Database(storage_error) => {
190
1
            assert!(storage_error.contains("mymessage"));
191
        }
192
        _ => unreachable!(),
193
    }
194
1
}