Skip to main content

dex_blob_cache/
error.rs

1// Copyright (c) 2026 Super Durable, Inc.
2//
3// Licensed under the Super Durable Source License 1.0.
4// You may not use this file except in compliance with the License.
5// See the LICENSE file in the repository root.
6//
7// SPDX-License-Identifier: LicenseRef-Super-Durable-1.0
8
9use std::error::Error;
10use std::fmt::{Display, Formatter};
11use std::io;
12
13#[derive(Debug)]
14/// Reports configuration, lifecycle, storage, or policy failures from [`crate::BlobCache`].
15pub enum BlobCacheError {
16    /// The operation requires an open cache, but [`crate::BlobCache::close`] already completed.
17    Closed,
18    /// Cache construction received an invalid directory, byte limit, or frequency counter count.
19    InvalidConfig(String),
20    /// A blob ID is empty, too large, or otherwise invalid.
21    InvalidBlob(String),
22    /// Existing content for a blob ID differs from the new immutable payload.
23    ContentMismatch(String),
24    /// A committed cache entry is malformed or fails integrity validation.
25    Corrupt(String),
26    /// On-disk state and the in-memory eviction policy could not be reconciled.
27    Reconciliation(String),
28    /// The admission or eviction policy failed.
29    Policy(String),
30    /// A filesystem operation failed.
31    Io {
32        /// Describes the filesystem operation that failed.
33        operation: String,
34        /// Preserves the underlying I/O error.
35        source: io::Error,
36    },
37}
38
39impl BlobCacheError {
40    pub(crate) fn io(operation: impl Into<String>, source: io::Error) -> Self {
41        Self::Io {
42            operation: operation.into(),
43            source,
44        }
45    }
46
47    pub(crate) fn is_missing_or_corrupt(&self) -> bool {
48        matches!(self, Self::Corrupt(_))
49            || matches!(self, Self::Io { source, .. } if source.kind() == io::ErrorKind::NotFound)
50    }
51}
52
53impl Display for BlobCacheError {
54    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
55        match self {
56            Self::Closed => formatter.write_str("blob cache is closed"),
57            Self::InvalidConfig(message) => {
58                write!(formatter, "invalid blob cache configuration: {message}")
59            }
60            Self::InvalidBlob(message) => write!(formatter, "invalid blob: {message}"),
61            Self::ContentMismatch(blob_id) => {
62                write!(formatter, "blob ID content mismatch: {blob_id:?}")
63            }
64            Self::Corrupt(message) => write!(formatter, "corrupt blob cache entry: {message}"),
65            Self::Reconciliation(message) => {
66                write!(formatter, "blob cache reconciliation failed: {message}")
67            }
68            Self::Policy(message) => write!(formatter, "blob cache policy failed: {message}"),
69            Self::Io { operation, source } => write!(formatter, "{operation}: {source}"),
70        }
71    }
72}
73
74impl Error for BlobCacheError {
75    fn source(&self) -> Option<&(dyn Error + 'static)> {
76        match self {
77            Self::Io { source, .. } => Some(source),
78            _ => None,
79        }
80    }
81}