1use std::io;
7use std::path::PathBuf;
8use thiserror::Error as ThisError;
9
10#[derive(ThisError, Debug)]
12pub enum Error {
13 #[error("I/O error: {0}")]
15 Io(#[from] io::Error),
16
17 #[error("File not found: {path}")]
19 FileNotFound { path: PathBuf },
20
21 #[error("Invalid file path: {reason}")]
23 InvalidPath { reason: String },
24
25 #[error("Path traversal detected: {path}")]
27 PathTraversalAttempt { path: PathBuf },
28
29 #[error("File too large ({size} bytes, max {max} bytes): {path}")]
31 FileTooLarge { path: PathBuf, size: u64, max: u64 },
32
33 #[error("Parse error: {reason}")]
35 ParseError { reason: String },
36
37 #[error("Configuration error: {reason}")]
39 ConfigError { reason: String },
40
41 #[error("Validation error: {reason}")]
43 ValidationError { reason: String },
44
45 #[error("Concurrent access conflict: {reason}")]
47 ConcurrencyError { reason: String },
48
49 #[error("Not found in graph: {key}")]
51 NotFound { key: String },
52
53 #[error("Error: {0}")]
55 Other(String),
56
57 #[error("Wrapped error: {0}")]
59 Wrapped(Box<dyn std::error::Error + Send + Sync>),
60}
61
62pub type Result<T> = std::result::Result<T, Error>;
64
65impl Error {
66 pub fn io(err: io::Error) -> Self {
68 Error::Io(err)
69 }
70
71 pub fn file_not_found(path: impl Into<PathBuf>) -> Self {
73 Error::FileNotFound { path: path.into() }
74 }
75
76 pub fn invalid_path(reason: impl Into<String>) -> Self {
78 Error::InvalidPath {
79 reason: reason.into(),
80 }
81 }
82
83 pub fn path_traversal(path: impl Into<PathBuf>) -> Self {
85 Error::PathTraversalAttempt { path: path.into() }
86 }
87
88 pub fn file_too_large(path: impl Into<PathBuf>, size: u64, max: u64) -> Self {
90 Error::FileTooLarge {
91 path: path.into(),
92 size,
93 max,
94 }
95 }
96
97 pub fn parse_error(reason: impl Into<String>) -> Self {
99 Error::ParseError {
100 reason: reason.into(),
101 }
102 }
103
104 pub fn config_error(reason: impl Into<String>) -> Self {
106 Error::ConfigError {
107 reason: reason.into(),
108 }
109 }
110
111 pub fn validation_error(reason: impl Into<String>) -> Self {
113 Error::ValidationError {
114 reason: reason.into(),
115 }
116 }
117
118 pub fn concurrency_error(reason: impl Into<String>) -> Self {
120 Error::ConcurrencyError {
121 reason: reason.into(),
122 }
123 }
124
125 pub fn not_found(key: impl Into<String>) -> Self {
127 Error::NotFound { key: key.into() }
128 }
129
130 pub fn other(msg: impl Into<String>) -> Self {
132 Error::Other(msg.into())
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_error_creation() {
142 let err = Error::file_not_found("/path/to/file");
143 assert!(err.to_string().contains("File not found"));
144
145 let err = Error::invalid_path("contains .. traversal");
146 assert!(err.to_string().contains("Invalid file path"));
147 }
148}