1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use crate::prelude::*;

/// The error type for `Storage` operations.
#[derive(Debug, Error)]
pub struct Error {
    kind: Kind,
}

impl Error {
    /// Returns the corresponding `Kind` for this error.
    #[must_use]
    pub fn kind(&self) -> &Kind {
        &self.kind
    }

    pub(crate) fn new(kind: Kind) -> Self {
        Self { kind }
    }

    pub(crate) fn file_pattern(path: PathBuf) -> Self {
        Self::new(Kind::WrongFileNamePattern(path))
    }

    pub(crate) fn validation(kind: ValidationErrorKind, cause: impl Into<String>) -> Self {
        let cause = cause.into();
        Self::new(Kind::Validation { kind, cause })
    }

    pub(crate) fn uninitialized() -> Self {
        Self::new(Kind::Uninitialized)
    }

    pub(crate) fn active_blob_not_set() -> Self {
        Self::new(Kind::ActiveBlobNotSet)
    }

    pub(crate) fn active_blob_doesnt_exist() -> Self {
        Self::new(Kind::ActiveBlobDoesntExist)
    }

    pub(crate) fn active_blob_already_exists() -> Self {
        Self::new(Kind::ActiveBlobExists)
    }

    pub(crate) fn not_found() -> Self {
        Self::new(Kind::RecordNotFound)
    }

    pub(crate) fn io(s: String) -> Self {
        Self::new(Kind::IO(s))
    }

    pub(crate) fn file_unavailable(kind: IOErrorKind) -> Self {
        Self::new(Kind::FileUnavailable(kind))
    }

    pub(crate) fn work_dir_unavailable(
        path: impl AsRef<Path>,
        msg: String,
        io_err_kind: IOErrorKind,
    ) -> Self {
        Self::new(Kind::WorkDirUnavailable {
            path: path.as_ref().into(),
            msg,
            io_err_kind,
        })
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        Debug::fmt(&self.kind, f)
    }
}

impl From<Kind> for Error {
    #[must_use]
    fn from(kind: Kind) -> Self {
        Self { kind }
    }
}

/// A list specifying categories of Storage error.
#[derive(Debug, Clone, PartialEq)]
pub enum Kind {
    /// Active blob not set, often initialization failed.
    ActiveBlobNotSet,
    /// Input configuration is wrong.
    WrongConfig,
    /// Probably storage initialization failed.
    Uninitialized,
    /// Record not found
    RecordNotFound,
    /// Work directory is locked by another storage.
    /// Or the operation lacked the necessary privileges to complete.
    /// Stop another storage or delete `*.lock` file
    WorkDirInUse,
    /// Happens when try to write/read from work dir that doesn't exist.
    /// In case when work dir wasn't created or disk was unmounted.
    /// Contains path to failed work dir, IOError description and IOErrorKind.
    WorkDirUnavailable {
        /// path of unavailable dir
        path: PathBuf,
        /// os error message (or custom one if we can't create directory during initialization)
        msg: String,
        /// IO Error Kind (`NotFound` or `Other`)
        io_err_kind: IOErrorKind,
    },
    /// Blob detects os errors during IO operation which indicate possible problems with disk
    FileUnavailable(IOErrorKind),
    /// Storage was initialized with different key size
    KeySizeMismatch,
    /// Active blob doesn't exist
    ActiveBlobDoesntExist,
    /// Active blob already exists
    ActiveBlobExists,
    /// Record with the same key and the same metadata already exists
    RecordExists,
    /// Any error not part of this list
    EmptyIndexBunch,
    /// Index error
    Index(String),
    /// Bincode serialization deserialization error
    Bincode(String),
    /// std::io::Error
    IO(String),
    /// Wrong file name pattern in config
    WrongFileNamePattern(PathBuf),
    /// Conversion error
    Conversion(String),
    /// Validation errors, eg. magic byte check
    Validation {
        /// Describes what check failed.
        kind: ValidationErrorKind,
        /// Description of an error cause.
        cause: String,
    },

    /// Other error
    Other,
}

/// Variants of validation errors.
#[derive(Debug, Clone, PartialEq)]
pub enum ValidationErrorKind {
    /// Blob key size.
    BlobKeySize,
    /// Blob magic byte.
    BlobMagicByte,
    /// Blob version.
    BlobVersion,
    /// Index checksum.
    IndexChecksum,
    /// Existing index write was successfully finished.
    IndexIsWritten,
    /// Index version.
    IndexVersion,
    /// Record data checksum.
    RecordDataChecksum,
    /// Record header checksum.
    RecordHeaderChecksum,
    /// Record magic byte.
    RecordMagicByte,
}

/// Convenient helper for downcasting anyhow error to pearl error.
pub trait AsPearlError {
    /// Performs conversion.
    fn as_pearl_error(&self) -> Option<&Error>;
}

impl AsPearlError for anyhow::Error {
    fn as_pearl_error(&self) -> Option<&Error> {
        self.downcast_ref()
    }
}