Skip to main content

cache_lite/
error.rs

1/*
2 * @filename: error.rs
3 * @description: Used for describing and handling cache errors
4 * @author: TaimWay <taimway@gmail.com>
5 * 
6 * Copyright (C) 2026 TaimWay
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in all
16 * copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27use std::fmt;
28use std::io;
29
30/// Cache library error types
31#[derive(Debug)]
32pub enum CacheError {
33    /// I/O operation failed
34    Io(io::Error),
35    /// Invalid cache name
36    InvalidName(String),
37    /// Configuration parsing error
38    ConfigParse(String),
39    /// Cache object not found
40    NotFound(String),
41    /// Permission denied for operation
42    PermissionDenied(String),
43    /// Cache object already exists
44    AlreadyExists(String),
45    /// Cache object has expired
46    Expired(String),
47    /// Invalid configuration provided
48    InvalidConfig(String),
49    /// Serialization/deserialization error
50    Serialization(String),
51    /// Invalid path or directory
52    InvalidPath(String),
53    /// Symbolic link detected (security risk)
54    SymlinkDetected(String),
55    /// Cache size limit exceeded
56    SizeLimitExceeded(String),
57    /// Cache file count limit exceeded
58    FileCountLimitExceeded(String),
59    /// Cache object corrupted
60    Corrupted(String),
61    /// Generic error with message
62    Generic(String),
63}
64
65impl fmt::Display for CacheError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            CacheError::Io(err) => write!(f, "I/O error: {}", err),
69            CacheError::InvalidName(msg) => write!(f, "Invalid cache name: {}", msg),
70            CacheError::ConfigParse(msg) => write!(f, "Configuration parse error: {}", msg),
71            CacheError::NotFound(msg) => write!(f, "Cache not found: {}", msg),
72            CacheError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
73            CacheError::AlreadyExists(msg) => write!(f, "Cache already exists: {}", msg),
74            CacheError::Expired(msg) => write!(f, "Cache expired: {}", msg),
75            CacheError::InvalidConfig(msg) => write!(f, "Invalid configuration: {}", msg),
76            CacheError::Serialization(msg) => write!(f, "Serialization error: {}", msg),
77            CacheError::InvalidPath(msg) => write!(f, "Invalid path: {}", msg),
78            CacheError::SymlinkDetected(msg) => write!(f, "Symbolic link detected: {}", msg),
79            CacheError::SizeLimitExceeded(msg) => write!(f, "Cache size limit exceeded: {}", msg),
80            CacheError::FileCountLimitExceeded(msg) => write!(f, "Cache file count limit exceeded: {}", msg),
81            CacheError::Corrupted(msg) => write!(f, "Cache corrupted: {}", msg),
82            CacheError::Generic(msg) => write!(f, "Error: {}", msg),
83        }
84    }
85}
86
87impl std::error::Error for CacheError {}
88
89impl From<io::Error> for CacheError {
90    fn from(err: io::Error) -> Self {
91        CacheError::Io(err)
92    }
93}
94
95impl From<serde_json::Error> for CacheError {
96    fn from(err: serde_json::Error) -> Self {
97        CacheError::ConfigParse(err.to_string())
98    }
99}
100
101impl CacheError {
102    /// Returns the error kind as a string
103    pub fn kind(&self) -> &'static str {
104        match self {
105            CacheError::Io(_) => "io",
106            CacheError::InvalidName(_) => "invalid_name",
107            CacheError::ConfigParse(_) => "config_parse",
108            CacheError::NotFound(_) => "not_found",
109            CacheError::PermissionDenied(_) => "permission_denied",
110            CacheError::AlreadyExists(_) => "already_exists",
111            CacheError::Expired(_) => "expired",
112            CacheError::InvalidConfig(_) => "invalid_config",
113            CacheError::Serialization(_) => "serialization",
114            CacheError::InvalidPath(_) => "invalid_path",
115            CacheError::SymlinkDetected(_) => "symlink_detected",
116            CacheError::SizeLimitExceeded(_) => "size_limit_exceeded",
117            CacheError::FileCountLimitExceeded(_) => "file_count_limit_exceeded",
118            CacheError::Corrupted(_) => "corrupted",
119            CacheError::Generic(_) => "generic",
120        }
121    }
122    
123    /// Returns the error message without the error kind prefix
124    pub fn message(&self) -> String {
125        match self {
126            CacheError::Io(err) => err.to_string(),
127            CacheError::InvalidName(msg) => msg.clone(),
128            CacheError::ConfigParse(msg) => msg.clone(),
129            CacheError::NotFound(msg) => msg.clone(),
130            CacheError::PermissionDenied(msg) => msg.clone(),
131            CacheError::AlreadyExists(msg) => msg.clone(),
132            CacheError::Expired(msg) => msg.clone(),
133            CacheError::InvalidConfig(msg) => msg.clone(),
134            CacheError::Serialization(msg) => msg.clone(),
135            CacheError::InvalidPath(msg) => msg.clone(),
136            CacheError::SymlinkDetected(msg) => msg.clone(),
137            CacheError::SizeLimitExceeded(msg) => msg.clone(),
138            CacheError::FileCountLimitExceeded(msg) => msg.clone(),
139            CacheError::Corrupted(msg) => msg.clone(),
140            CacheError::Generic(msg) => msg.clone(),
141        }
142    }
143    
144    /// Creates a new generic error
145    pub fn new<S: Into<String>>(message: S) -> Self {
146        CacheError::Generic(message.into())
147    }
148    
149    /// Checks if the error is an I/O error
150    pub fn is_io_error(&self) -> bool {
151        matches!(self, CacheError::Io(_))
152    }
153    
154    /// Checks if the error indicates something wasn't found
155    pub fn is_not_found(&self) -> bool {
156        matches!(self, CacheError::NotFound(_))
157    }
158    
159    /// Checks if the error indicates permission was denied
160    pub fn is_permission_denied(&self) -> bool {
161        matches!(self, CacheError::PermissionDenied(_))
162    }
163}