Mountain/Error/
FileSystemError.rs

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