##// END OF EJS Templates
rust: Introduce an `HgError` enum for common error cases...
Simon Sapin -
r47167:39e94078 default
parent child Browse files
Show More
@@ -0,0 +1,111 b''
1 use std::fmt;
2
3 /// Common error cases that can happen in many different APIs
4 #[derive(Debug)]
5 pub enum HgError {
6 IoError {
7 error: std::io::Error,
8 context: IoErrorContext,
9 },
10
11 /// A file under `.hg/` normally only written by Mercurial
12 ///
13 /// The given string is a short explanation for users, not intended to be
14 /// machine-readable.
15 CorruptedRepository(String),
16
17 /// The respository or requested operation involves a feature not
18 /// supported by the Rust implementation. Falling back to the Python
19 /// implementation may or may not work.
20 ///
21 /// The given string is a short explanation for users, not intended to be
22 /// machine-readable.
23 UnsupportedFeature(String),
24 }
25
26 /// Details about where an I/O error happened
27 #[derive(Debug, derive_more::From)]
28 pub enum IoErrorContext {
29 /// A filesystem operation returned `std::io::Error`
30 #[from]
31 File(std::path::PathBuf),
32 /// `std::env::current_dir` returned `std::io::Error`
33 CurrentDir,
34 }
35
36 impl HgError {
37 pub fn corrupted(explanation: impl Into<String>) -> Self {
38 HgError::CorruptedRepository(explanation.into())
39 }
40 }
41
42 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
43 impl fmt::Display for HgError {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 match self {
46 HgError::IoError { error, context } => {
47 write!(f, "{}: {}", error, context)
48 }
49 HgError::CorruptedRepository(explanation) => {
50 write!(f, "corrupted repository: {}", explanation)
51 }
52 HgError::UnsupportedFeature(explanation) => {
53 write!(f, "unsupported feature: {}", explanation)
54 }
55 }
56 }
57 }
58
59 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
60 impl fmt::Display for IoErrorContext {
61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 match self {
63 IoErrorContext::File(path) => path.display().fmt(f),
64 IoErrorContext::CurrentDir => f.write_str("current directory"),
65 }
66 }
67 }
68
69 pub trait IoResultExt<T> {
70 /// Annotate a possible I/O error as related to a file at the given path.
71 ///
72 /// This allows printing something like “File not found: example.txt”
73 /// instead of just “File not found”.
74 ///
75 /// Converts a `Result` with `std::io::Error` into one with `HgError`.
76 fn for_file(self, path: &std::path::Path) -> Result<T, HgError>;
77 }
78
79 impl<T> IoResultExt<T> for std::io::Result<T> {
80 fn for_file(self, path: &std::path::Path) -> Result<T, HgError> {
81 self.map_err(|error| HgError::IoError {
82 error,
83 context: IoErrorContext::File(path.to_owned()),
84 })
85 }
86 }
87
88 pub trait HgResultExt<T> {
89 /// Handle missing files separately from other I/O error cases.
90 ///
91 /// Wraps the `Ok` type in an `Option`:
92 ///
93 /// * `Ok(x)` becomes `Ok(Some(x))`
94 /// * An I/O "not found" error becomes `Ok(None)`
95 /// * Other errors are unchanged
96 fn io_not_found_as_none(self) -> Result<Option<T>, HgError>;
97 }
98
99 impl<T> HgResultExt<T> for Result<T, HgError> {
100 fn io_not_found_as_none(self) -> Result<Option<T>, HgError> {
101 match self {
102 Ok(x) => Ok(Some(x)),
103 Err(HgError::IoError { error, .. })
104 if error.kind() == std::io::ErrorKind::NotFound =>
105 {
106 Ok(None)
107 }
108 Err(other_error) => Err(other_error),
109 }
110 }
111 }
@@ -5,6 +5,7 b''
5 // GNU General Public License version 2 or any later version.
5 // GNU General Public License version 2 or any later version.
6 mod ancestors;
6 mod ancestors;
7 pub mod dagops;
7 pub mod dagops;
8 pub mod errors;
8 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
9 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
9 mod dirstate;
10 mod dirstate;
10 pub mod discovery;
11 pub mod discovery;
General Comments 0
You need to be logged in to leave comments. Login now