1
1
//! Error and Result definitions
2
2
3
- use std:: fmt:: { Display , Formatter } ;
4
- use std:: io:: Error ;
3
+ use std:: { error, fmt, io} ;
5
4
6
5
/// The error type of this crate
7
6
#[ derive( Debug ) ]
8
- pub enum VfsError {
9
- /// A generic IO error
10
- IoError ( std:: io:: Error ) ,
7
+ pub struct VfsError {
8
+ /// The path this error was encountered in
9
+ path : String ,
10
+ /// The kind of error
11
+ kind : VfsErrorKind ,
12
+ /// An optional human-readable string describing the context for this error
13
+ ///
14
+ /// If not provided, a generic context message is used
15
+ context : String ,
16
+ /// The underlying error
17
+ cause : Option < Box < VfsError > > ,
18
+ }
11
19
12
- /// The file or directory at the given path could not be found
13
- FileNotFound {
14
- /// The path of the file not found
15
- path : String ,
16
- } ,
20
+ /// The only way to create a VfsError is via a VfsErrorKind
21
+ ///
22
+ /// This conversion implements certain normalizations
23
+ impl From < VfsErrorKind > for VfsError {
24
+ fn from ( kind : VfsErrorKind ) -> Self {
25
+ // Normalize the error here before we return it
26
+ let kind = match kind {
27
+ VfsErrorKind :: IoError ( io) => match io. kind ( ) {
28
+ io:: ErrorKind :: NotFound => VfsErrorKind :: FileNotFound ,
29
+ io:: ErrorKind :: Unsupported => VfsErrorKind :: NotSupported ,
30
+ _ => VfsErrorKind :: IoError ( io) ,
31
+ } ,
32
+ // Remaining kinda are passed through as-is
33
+ other => other,
34
+ } ;
17
35
18
- /// The given path is invalid, e.g. because contains '.' or '..'
19
- InvalidPath {
20
- /// The invalid path
21
- path : String ,
22
- } ,
36
+ Self {
37
+ // TODO (Techno): See if this could be checked at compile-time to make sure the VFS abstraction
38
+ // never forgets to add a path. Might need a separate error type for FS impls vs VFS
39
+ path : "PATH NOT FILLED BY VFS LAYER" . into ( ) ,
40
+ kind,
41
+ context : "An error occured" . into ( ) ,
42
+ cause : None ,
43
+ }
44
+ }
45
+ }
23
46
24
- /// Generic error variant
25
- Other {
26
- /// The generic error message
27
- message : String ,
28
- } ,
29
-
30
- /// Generic error context, used for adding context to an error (like a path)
31
- WithContext {
32
- /// The context error message
33
- context : String ,
34
- /// The underlying error
35
- cause : Box < VfsError > ,
36
- } ,
47
+ impl From < io:: Error > for VfsError {
48
+ fn from ( err : io:: Error ) -> Self {
49
+ Self :: from ( VfsErrorKind :: IoError ( err) )
50
+ }
51
+ }
37
52
38
- /// Functionality not supported by this filesystem
39
- NotSupported ,
53
+ impl VfsError {
54
+ // Path filled by the VFS crate rather than the implementations
55
+ pub ( crate ) fn with_path ( mut self , path : impl Into < String > ) -> Self {
56
+ self . path = path. into ( ) ;
57
+ self
58
+ }
59
+
60
+ pub fn with_context < C , F > ( mut self , context : F ) -> Self
61
+ where
62
+ C : fmt:: Display + Send + Sync + ' static ,
63
+ F : FnOnce ( ) -> C ,
64
+ {
65
+ self . context = context ( ) . to_string ( ) ;
66
+ self
67
+ }
68
+
69
+ pub fn with_cause ( mut self , cause : VfsError ) -> Self {
70
+ self . cause = Some ( Box :: new ( cause) ) ;
71
+ self
72
+ }
73
+
74
+ pub fn kind ( & self ) -> & VfsErrorKind {
75
+ & self . kind
76
+ }
77
+ }
78
+
79
+ impl fmt:: Display for VfsError {
80
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
81
+ write ! ( f, "{} for '{}': {}" , self . context, self . path, self . kind( ) )
82
+ }
40
83
}
41
84
42
- impl std :: error:: Error for VfsError {
43
- fn source ( & self ) -> Option < & ( dyn std :: error:: Error + ' static ) > {
44
- if let Self :: WithContext { cause, .. } = self {
85
+ impl error:: Error for VfsError {
86
+ fn source ( & self ) -> Option < & ( dyn error:: Error + ' static ) > {
87
+ if let Some ( cause) = & self . cause {
45
88
Some ( cause)
46
89
} else {
47
90
None
48
91
}
49
92
}
50
93
}
51
94
52
- impl From < String > for VfsError {
53
- fn from ( message : String ) -> Self {
54
- VfsError :: Other { message }
55
- }
56
- }
95
+ /// The kinds of errors that can occur
96
+ #[ derive( Debug ) ]
97
+ pub enum VfsErrorKind {
98
+ /// A generic I/O error
99
+ ///
100
+ /// Certain standard I/O errors are normalized to their VfsErrorKind counterparts
101
+ IoError ( io:: Error ) ,
57
102
58
- impl From < std:: io:: Error > for VfsError {
59
- fn from ( cause : Error ) -> Self {
60
- VfsError :: IoError ( cause)
61
- }
103
+ /// The file or directory at the given path could not be found
104
+ FileNotFound ,
105
+
106
+ /// The given path is invalid, e.g. because contains '.' or '..'
107
+ InvalidPath ,
108
+
109
+ /// Generic error variant
110
+ Other ( String ) ,
111
+
112
+ /// Functionality not supported by this filesystem
113
+ NotSupported ,
62
114
}
63
115
64
- impl std :: fmt:: Display for VfsError {
65
- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std :: fmt:: Result {
116
+ impl fmt:: Display for VfsErrorKind {
117
+ fn fmt ( & self , f : & mut fmt :: Formatter < ' _ > ) -> fmt:: Result {
66
118
match self {
67
- VfsError :: IoError ( cause) => {
119
+ VfsErrorKind :: IoError ( cause) => {
68
120
write ! ( f, "IO error: {}" , cause)
69
121
}
70
- VfsError :: FileNotFound { path } => {
71
- write ! ( f, "The file or directory `{}` could not be found" , path )
122
+ VfsErrorKind :: FileNotFound => {
123
+ write ! ( f, "The file or directory could not be found" )
72
124
}
73
- VfsError :: InvalidPath { path } => {
74
- write ! ( f, "The path `{}` is invalid" , path )
125
+ VfsErrorKind :: InvalidPath => {
126
+ write ! ( f, "The path is invalid" )
75
127
}
76
- VfsError :: Other { message } => {
128
+ VfsErrorKind :: Other ( message) => {
77
129
write ! ( f, "FileSystem error: {}" , message)
78
130
}
79
- VfsError :: WithContext { context, cause } => {
80
- write ! ( f, "{}, cause: {}" , context, cause)
81
- }
82
- VfsError :: NotSupported => {
131
+ VfsErrorKind :: NotSupported => {
83
132
write ! ( f, "Functionality not supported by this filesystem" )
84
133
}
85
134
}
@@ -88,24 +137,3 @@ impl std::fmt::Display for VfsError {
88
137
89
138
/// The result type of this crate
90
139
pub type VfsResult < T > = std:: result:: Result < T , VfsError > ;
91
-
92
- /// Result extension trait to add context information
93
- pub ( crate ) trait VfsResultExt < T > {
94
- fn with_context < C , F > ( self , f : F ) -> VfsResult < T >
95
- where
96
- C : Display + Send + Sync + ' static ,
97
- F : FnOnce ( ) -> C ;
98
- }
99
-
100
- impl < T > VfsResultExt < T > for VfsResult < T > {
101
- fn with_context < C , F > ( self , context : F ) -> VfsResult < T >
102
- where
103
- C : Display + Send + Sync + ' static ,
104
- F : FnOnce ( ) -> C ,
105
- {
106
- self . map_err ( |error| VfsError :: WithContext {
107
- context : context ( ) . to_string ( ) ,
108
- cause : Box :: new ( error) ,
109
- } )
110
- }
111
- }
0 commit comments