bonsaidb_local/
error.rs

1use std::convert::Infallible;
2use std::fmt::Display;
3use std::str::Utf8Error;
4use std::string::FromUtf8Error;
5use std::sync::Arc;
6
7use bonsaidb_core::permissions::PermissionDenied;
8use bonsaidb_core::pubsub::{Disconnected, TryReceiveError};
9use bonsaidb_core::schema::{view, InsertError, InvalidNameError};
10use bonsaidb_core::AnyError;
11use nebari::AbortError;
12
13use crate::database::compat::UnknownVersion;
14
15/// Errors that can occur from interacting with storage.
16#[derive(thiserror::Error, Debug)]
17pub 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
80impl 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
86impl<T> From<InsertError<T>> for Error {
87    fn from(err: InsertError<T>) -> Self {
88        Self::Core(err.error)
89    }
90}
91
92impl From<flume::RecvError> for Error {
93    fn from(_: flume::RecvError) -> Self {
94        Self::InternalCommunication
95    }
96}
97
98impl From<TryReceiveError> for Error {
99    fn from(_: TryReceiveError) -> Self {
100        Self::InternalCommunication
101    }
102}
103
104impl From<Disconnected> for Error {
105    fn from(_: Disconnected) -> Self {
106        Self::InternalCommunication
107    }
108}
109
110impl From<bincode::Error> for Error {
111    fn from(err: bincode::Error) -> Self {
112        Self::other("bincode", err)
113    }
114}
115
116impl<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")]
123impl 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")]
130impl 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")]
137impl 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")]
144impl From<tokio::sync::oneshot::error::TryRecvError> for Error {
145    fn from(_: tokio::sync::oneshot::error::TryRecvError) -> Self {
146        Self::InternalCommunication
147    }
148}
149
150impl From<Error> for bonsaidb_core::Error {
151    fn from(err: Error) -> Self {
152        match err {
153            Error::View(view::Error::Core(core)) | Error::Core(core) => core,
154            other => Self::other("bonsaidb-local", other),
155        }
156    }
157}
158
159impl 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
168impl From<FromUtf8Error> for Error {
169    fn from(err: FromUtf8Error) -> Self {
170        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
171    }
172}
173
174impl From<Utf8Error> for Error {
175    fn from(err: Utf8Error) -> Self {
176        Self::Core(bonsaidb_core::Error::InvalidUnicode(err.to_string()))
177    }
178}
179
180impl From<InvalidNameError> for Error {
181    fn from(err: InvalidNameError) -> Self {
182        Self::Core(bonsaidb_core::Error::from(err))
183    }
184}
185
186impl 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
195impl From<AbortError<Error>> for Error {
196    fn from(err: AbortError<Error>) -> Self {
197        match err {
198            AbortError::Nebari(error) => Self::Nebari(error),
199            AbortError::Other(error) => error,
200        }
201    }
202}
203
204impl From<PermissionDenied> for Error {
205    fn from(err: PermissionDenied) -> Self {
206        Self::Core(bonsaidb_core::Error::from(err))
207    }
208}
209
210#[test]
211fn test_converting_error() {
212    use serde::ser::Error as _;
213    let err: bonsaidb_core::Error = Error::Serialization(pot::Error::custom("mymessage")).into();
214    match err {
215        bonsaidb_core::Error::Other { error, .. } => {
216            assert!(error.contains("mymessage"));
217        }
218        _ => unreachable!(),
219    }
220}