Skip to main content

Mountain/Error/
FileSystemError.rs

1//! # File System Error Types
2//!
3//! File system operation error types for Mountain.
4//! Covers not-found, permission denial, raw I/O failures, invalid
5//! paths, directory-state violations, and file/directory type
6//! mismatches.
7
8use std::{error::Error as StdError, fmt, path::PathBuf};
9
10use serde::{Deserialize, Serialize};
11
12use super::CoreError::{ErrorContext, ErrorKind, ErrorSeverity, MountainError};
13
14/// File system operation error types.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub enum FileSystemError {
17	/// File not found.
18	FileNotFound { context:ErrorContext, path:PathBuf },
19
20	/// Permission denied.
21	PermissionDenied { context:ErrorContext, path:PathBuf },
22
23	/// I/O error occurred.
24	IOError { context:ErrorContext, path:Option<PathBuf>, operation:String },
25
26	/// Invalid path.
27	InvalidPath { context:ErrorContext, path:PathBuf },
28
29	/// Directory not empty.
30	DirectoryNotEmpty { context:ErrorContext, path:PathBuf },
31
32	/// File already exists.
33	FileAlreadyExists { context:ErrorContext, path:PathBuf },
34
35	/// Not a directory.
36	NotADirectory { context:ErrorContext, path:PathBuf },
37
38	/// Not a file.
39	NotAFile { context:ErrorContext, path:PathBuf },
40}
41
42impl FileSystemError {
43	/// Get the error context.
44	pub fn context(&self) -> &ErrorContext {
45		match self {
46			FileSystemError::FileNotFound { context, .. } => context,
47
48			FileSystemError::PermissionDenied { context, .. } => context,
49
50			FileSystemError::IOError { context, .. } => context,
51
52			FileSystemError::InvalidPath { context, .. } => context,
53
54			FileSystemError::DirectoryNotEmpty { context, .. } => context,
55
56			FileSystemError::FileAlreadyExists { context, .. } => context,
57
58			FileSystemError::NotADirectory { context, .. } => context,
59
60			FileSystemError::NotAFile { context, .. } => context,
61		}
62	}
63
64	/// Create a file not found error.
65	pub fn file_not_found(path:impl Into<PathBuf>) -> Self {
66		let path = path.into();
67
68		Self::FileNotFound {
69			context:ErrorContext::new(format!("File not found: {}", path.display()))
70				.with_kind(ErrorKind::FileSystem)
71				.with_severity(ErrorSeverity::Error),
72
73			path,
74		}
75	}
76
77	/// Create a permission denied error.
78	pub fn permission_denied(path:impl Into<PathBuf>) -> Self {
79		let path = path.into();
80
81		Self::PermissionDenied {
82			context:ErrorContext::new(format!("Permission denied: {}", path.display()))
83				.with_kind(ErrorKind::FileSystem)
84				.with_severity(ErrorSeverity::Error),
85
86			path,
87		}
88	}
89
90	/// Create an I/O error.
91	pub fn io_error(operation:impl Into<String>, path:Option<PathBuf>, message:impl Into<String>) -> Self {
92		let operation_str = operation.into();
93
94		Self::IOError {
95			context:ErrorContext::new(message)
96				.with_kind(ErrorKind::FileSystem)
97				.with_severity(ErrorSeverity::Error)
98				.with_operation(operation_str.clone()),
99
100			path,
101
102			operation:operation_str,
103		}
104	}
105
106	/// Create an invalid path error.
107	pub fn invalid_path(path:impl Into<PathBuf>) -> Self {
108		let path = path.into();
109
110		Self::InvalidPath {
111			context:ErrorContext::new(format!("Invalid path: {}", path.display()))
112				.with_kind(ErrorKind::FileSystem)
113				.with_severity(ErrorSeverity::Error),
114
115			path,
116		}
117	}
118
119	/// Get the affected path.
120	pub fn path(&self) -> Option<&PathBuf> {
121		match self {
122			FileSystemError::FileNotFound { path, .. } => Some(path),
123
124			FileSystemError::PermissionDenied { path, .. } => Some(path),
125
126			FileSystemError::IOError { path, .. } => path.as_ref(),
127
128			FileSystemError::InvalidPath { path, .. } => Some(path),
129
130			FileSystemError::DirectoryNotEmpty { path, .. } => Some(path),
131
132			FileSystemError::FileAlreadyExists { path, .. } => Some(path),
133
134			FileSystemError::NotADirectory { path, .. } => Some(path),
135
136			FileSystemError::NotAFile { path, .. } => Some(path),
137		}
138	}
139}
140
141impl fmt::Display for FileSystemError {
142	fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
143		write!(f, "{}", self.context())?;
144
145		if let Some(path) = self.path() {
146			write!(f, " (path: {})", path.display())?;
147		}
148
149		Ok(())
150	}
151}
152
153impl StdError for FileSystemError {}
154
155impl From<FileSystemError> for MountainError {
156	fn from(err:FileSystemError) -> Self { MountainError::new(err.context().clone()).with_source(err.to_string()) }
157}
158
159impl From<std::io::Error> for FileSystemError {
160	fn from(err:std::io::Error) -> Self { Self::io_error("I/O operation", None, err.to_string()) }
161}