]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use boxed::Box; | |
c34b1796 AL |
12 | use convert::Into; |
13 | use error; | |
85aaf69f | 14 | use fmt; |
9346a6ac | 15 | use marker::{Send, Sync}; |
85aaf69f SL |
16 | use option::Option::{self, Some, None}; |
17 | use result; | |
85aaf69f SL |
18 | use sys; |
19 | ||
c1a9b12d SL |
20 | /// A specialized [`Result`][result] type for I/O operations. |
21 | /// | |
22 | /// [result]: ../result/enum.Result.html | |
23 | /// | |
24 | /// This type is broadly used across `std::io` for any operation which may | |
25 | /// produce an error. | |
85aaf69f SL |
26 | /// |
27 | /// This typedef is generally used to avoid writing out `io::Error` directly and | |
c1a9b12d SL |
28 | /// is otherwise a direct mapping to `Result`. |
29 | /// | |
30 | /// While usual Rust style is to import types directly, aliases of `Result` | |
31 | /// often are not, to make it easier to distinguish between them. `Result` is | |
32 | /// generally assumed to be `std::result::Result`, and so users of this alias | |
33 | /// will generally use `io::Result` instead of shadowing the prelude's import | |
34 | /// of `std::result::Result`. | |
35 | /// | |
36 | /// # Examples | |
37 | /// | |
38 | /// A convenience function that bubbles an `io::Result` to its caller: | |
39 | /// | |
40 | /// ``` | |
41 | /// use std::io; | |
42 | /// | |
43 | /// fn get_string() -> io::Result<String> { | |
44 | /// let mut buffer = String::new(); | |
45 | /// | |
46 | /// try!(io::stdin().read_line(&mut buffer)); | |
47 | /// | |
48 | /// Ok(buffer) | |
49 | /// } | |
50 | /// ``` | |
c34b1796 | 51 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
52 | pub type Result<T> = result::Result<T, Error>; |
53 | ||
54 | /// The error type for I/O operations of the `Read`, `Write`, `Seek`, and | |
55 | /// associated traits. | |
56 | /// | |
57 | /// Errors mostly originate from the underlying OS, but custom instances of | |
58 | /// `Error` can be created with crafted error messages and a particular value of | |
59 | /// `ErrorKind`. | |
c34b1796 AL |
60 | #[derive(Debug)] |
61 | #[stable(feature = "rust1", since = "1.0.0")] | |
85aaf69f SL |
62 | pub struct Error { |
63 | repr: Repr, | |
64 | } | |
65 | ||
85aaf69f SL |
66 | enum Repr { |
67 | Os(i32), | |
68 | Custom(Box<Custom>), | |
69 | } | |
70 | ||
c34b1796 | 71 | #[derive(Debug)] |
85aaf69f SL |
72 | struct Custom { |
73 | kind: ErrorKind, | |
9346a6ac | 74 | error: Box<error::Error+Send+Sync>, |
85aaf69f SL |
75 | } |
76 | ||
77 | /// A list specifying general categories of I/O error. | |
c34b1796 AL |
78 | /// |
79 | /// This list is intended to grow over time and it is not recommended to | |
80 | /// exhaustively match against it. | |
85aaf69f | 81 | #[derive(Copy, PartialEq, Eq, Clone, Debug)] |
c34b1796 | 82 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 83 | pub enum ErrorKind { |
c34b1796 AL |
84 | /// An entity was not found, often a file. |
85 | #[stable(feature = "rust1", since = "1.0.0")] | |
86 | NotFound, | |
87 | /// The operation lacked the necessary privileges to complete. | |
88 | #[stable(feature = "rust1", since = "1.0.0")] | |
85aaf69f SL |
89 | PermissionDenied, |
90 | /// The connection was refused by the remote server. | |
c34b1796 | 91 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
92 | ConnectionRefused, |
93 | /// The connection was reset by the remote server. | |
c34b1796 | 94 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
95 | ConnectionReset, |
96 | /// The connection was aborted (terminated) by the remote server. | |
c34b1796 | 97 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
98 | ConnectionAborted, |
99 | /// The network operation failed because it was not connected yet. | |
c34b1796 | 100 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 101 | NotConnected, |
c34b1796 AL |
102 | /// A socket address could not be bound because the address is already in |
103 | /// use elsewhere. | |
104 | #[stable(feature = "rust1", since = "1.0.0")] | |
105 | AddrInUse, | |
106 | /// A nonexistent interface was requested or the requested address was not | |
107 | /// local. | |
108 | #[stable(feature = "rust1", since = "1.0.0")] | |
109 | AddrNotAvailable, | |
85aaf69f | 110 | /// The operation failed because a pipe was closed. |
c34b1796 | 111 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 112 | BrokenPipe, |
c34b1796 AL |
113 | /// An entity already exists, often a file. |
114 | #[stable(feature = "rust1", since = "1.0.0")] | |
115 | AlreadyExists, | |
116 | /// The operation needs to block to complete, but the blocking operation was | |
117 | /// requested to not occur. | |
118 | #[stable(feature = "rust1", since = "1.0.0")] | |
119 | WouldBlock, | |
120 | /// A parameter was incorrect. | |
121 | #[stable(feature = "rust1", since = "1.0.0")] | |
85aaf69f | 122 | InvalidInput, |
62682a34 SL |
123 | /// Data not valid for the operation were encountered. |
124 | /// | |
125 | /// Unlike `InvalidInput`, this typically means that the operation | |
126 | /// parameters were valid, however the error was caused by malformed | |
127 | /// input data. | |
128 | #[stable(feature = "io_invalid_data", since = "1.2.0")] | |
129 | InvalidData, | |
85aaf69f | 130 | /// The I/O operation's timeout expired, causing it to be canceled. |
c34b1796 | 131 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
132 | TimedOut, |
133 | /// An error returned when an operation could not be completed because a | |
134 | /// call to `write` returned `Ok(0)`. | |
135 | /// | |
136 | /// This typically means that an operation could only succeed if it wrote a | |
137 | /// particular number of bytes but only a smaller number of bytes could be | |
138 | /// written. | |
c34b1796 | 139 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 140 | WriteZero, |
c34b1796 AL |
141 | /// This operation was interrupted. |
142 | /// | |
143 | /// Interrupted operations can typically be retried. | |
144 | #[stable(feature = "rust1", since = "1.0.0")] | |
85aaf69f SL |
145 | Interrupted, |
146 | /// Any I/O error not part of this list. | |
c34b1796 | 147 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 148 | Other, |
c34b1796 AL |
149 | |
150 | /// Any I/O error not part of this list. | |
62682a34 | 151 | #[unstable(feature = "io_error_internals", |
c34b1796 AL |
152 | reason = "better expressed through extensible enums that this \ |
153 | enum cannot be exhaustively matched against")] | |
154 | #[doc(hidden)] | |
155 | __Nonexhaustive, | |
85aaf69f SL |
156 | } |
157 | ||
158 | impl Error { | |
c34b1796 AL |
159 | /// Creates a new I/O error from a known kind of error as well as an |
160 | /// arbitrary error payload. | |
161 | /// | |
162 | /// This function is used to generically create I/O errors which do not | |
163 | /// originate from the OS itself. The `error` argument is an arbitrary | |
62682a34 | 164 | /// payload which will be contained in this `Error`. |
c34b1796 AL |
165 | /// |
166 | /// # Examples | |
167 | /// | |
168 | /// ``` | |
169 | /// use std::io::{Error, ErrorKind}; | |
170 | /// | |
171 | /// // errors can be created from strings | |
172 | /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); | |
173 | /// | |
174 | /// // errors can also be created from other errors | |
175 | /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); | |
176 | /// ``` | |
177 | #[stable(feature = "rust1", since = "1.0.0")] | |
178 | pub fn new<E>(kind: ErrorKind, error: E) -> Error | |
9346a6ac | 179 | where E: Into<Box<error::Error+Send+Sync>> |
c34b1796 | 180 | { |
85aaf69f SL |
181 | Error { |
182 | repr: Repr::Custom(Box::new(Custom { | |
183 | kind: kind, | |
c34b1796 | 184 | error: error.into(), |
85aaf69f SL |
185 | })) |
186 | } | |
187 | } | |
188 | ||
189 | /// Returns an error representing the last OS error which occurred. | |
190 | /// | |
191 | /// This function reads the value of `errno` for the target platform (e.g. | |
192 | /// `GetLastError` on Windows) and will return a corresponding instance of | |
193 | /// `Error` for the error code. | |
c34b1796 | 194 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 195 | pub fn last_os_error() -> Error { |
9346a6ac | 196 | Error::from_raw_os_error(sys::os::errno() as i32) |
85aaf69f SL |
197 | } |
198 | ||
199 | /// Creates a new instance of an `Error` from a particular OS error code. | |
9346a6ac AL |
200 | #[stable(feature = "rust1", since = "1.0.0")] |
201 | pub fn from_raw_os_error(code: i32) -> Error { | |
85aaf69f SL |
202 | Error { repr: Repr::Os(code) } |
203 | } | |
204 | ||
c34b1796 AL |
205 | /// Returns the OS error that this error represents (if any). |
206 | /// | |
62682a34 SL |
207 | /// If this `Error` was constructed via `last_os_error` or |
208 | /// `from_raw_os_error`, then this function will return `Some`, otherwise | |
209 | /// it will return `None`. | |
c34b1796 AL |
210 | #[stable(feature = "rust1", since = "1.0.0")] |
211 | pub fn raw_os_error(&self) -> Option<i32> { | |
85aaf69f | 212 | match self.repr { |
c34b1796 AL |
213 | Repr::Os(i) => Some(i), |
214 | Repr::Custom(..) => None, | |
85aaf69f SL |
215 | } |
216 | } | |
217 | ||
62682a34 SL |
218 | /// Returns a reference to the inner error wrapped by this error (if any). |
219 | /// | |
220 | /// If this `Error` was constructed via `new` then this function will | |
221 | /// return `Some`, otherwise it will return `None`. | |
c1a9b12d | 222 | #[stable(feature = "io_error_inner", since = "1.3.0")] |
62682a34 SL |
223 | pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { |
224 | match self.repr { | |
225 | Repr::Os(..) => None, | |
226 | Repr::Custom(ref c) => Some(&*c.error), | |
227 | } | |
228 | } | |
229 | ||
230 | /// Returns a mutable reference to the inner error wrapped by this error | |
231 | /// (if any). | |
232 | /// | |
233 | /// If this `Error` was constructed via `new` then this function will | |
234 | /// return `Some`, otherwise it will return `None`. | |
c1a9b12d | 235 | #[stable(feature = "io_error_inner", since = "1.3.0")] |
62682a34 SL |
236 | pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { |
237 | match self.repr { | |
238 | Repr::Os(..) => None, | |
239 | Repr::Custom(ref mut c) => Some(&mut *c.error), | |
240 | } | |
241 | } | |
242 | ||
243 | /// Consumes the `Error`, returning its inner error (if any). | |
244 | /// | |
245 | /// If this `Error` was constructed via `new` then this function will | |
246 | /// return `Some`, otherwise it will return `None`. | |
c1a9b12d | 247 | #[stable(feature = "io_error_inner", since = "1.3.0")] |
62682a34 SL |
248 | pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> { |
249 | match self.repr { | |
250 | Repr::Os(..) => None, | |
251 | Repr::Custom(c) => Some(c.error) | |
252 | } | |
253 | } | |
254 | ||
9346a6ac | 255 | /// Returns the corresponding `ErrorKind` for this error. |
c34b1796 AL |
256 | #[stable(feature = "rust1", since = "1.0.0")] |
257 | pub fn kind(&self) -> ErrorKind { | |
85aaf69f | 258 | match self.repr { |
c34b1796 AL |
259 | Repr::Os(code) => sys::decode_error_kind(code), |
260 | Repr::Custom(ref c) => c.kind, | |
85aaf69f SL |
261 | } |
262 | } | |
263 | } | |
264 | ||
62682a34 SL |
265 | impl fmt::Debug for Repr { |
266 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
267 | match self { | |
268 | &Repr::Os(ref code) => | |
269 | fmt.debug_struct("Os").field("code", code) | |
270 | .field("message", &sys::os::error_string(*code)).finish(), | |
271 | &Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(), | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
c34b1796 | 276 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
277 | impl fmt::Display for Error { |
278 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
279 | match self.repr { | |
280 | Repr::Os(code) => { | |
281 | let detail = sys::os::error_string(code); | |
282 | write!(fmt, "{} (os error {})", detail, code) | |
283 | } | |
c34b1796 | 284 | Repr::Custom(ref c) => c.error.fmt(fmt), |
85aaf69f SL |
285 | } |
286 | } | |
287 | } | |
288 | ||
c34b1796 AL |
289 | #[stable(feature = "rust1", since = "1.0.0")] |
290 | impl error::Error for Error { | |
85aaf69f SL |
291 | fn description(&self) -> &str { |
292 | match self.repr { | |
293 | Repr::Os(..) => "os error", | |
c34b1796 | 294 | Repr::Custom(ref c) => c.error.description(), |
85aaf69f SL |
295 | } |
296 | } | |
62682a34 SL |
297 | |
298 | fn cause(&self) -> Option<&error::Error> { | |
299 | match self.repr { | |
300 | Repr::Os(..) => None, | |
301 | Repr::Custom(ref c) => c.error.cause(), | |
302 | } | |
303 | } | |
85aaf69f | 304 | } |
9346a6ac AL |
305 | |
306 | fn _assert_error_is_sync_send() { | |
307 | fn _is_sync_send<T: Sync+Send>() {} | |
308 | _is_sync_send::<Error>(); | |
309 | } | |
62682a34 SL |
310 | |
311 | #[cfg(test)] | |
312 | mod test { | |
313 | use prelude::v1::*; | |
314 | use super::{Error, ErrorKind}; | |
315 | use error; | |
316 | use error::Error as error_Error; | |
317 | use fmt; | |
318 | use sys::os::error_string; | |
319 | ||
320 | #[test] | |
321 | fn test_debug_error() { | |
322 | let code = 6; | |
323 | let msg = error_string(code); | |
324 | let err = Error { repr: super::Repr::Os(code) }; | |
325 | let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg); | |
326 | assert_eq!(format!("{:?}", err), expected); | |
327 | } | |
328 | ||
329 | #[test] | |
330 | fn test_downcasting() { | |
331 | #[derive(Debug)] | |
332 | struct TestError; | |
333 | ||
334 | impl fmt::Display for TestError { | |
335 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
336 | Ok(()) | |
337 | } | |
338 | } | |
339 | ||
340 | impl error::Error for TestError { | |
341 | fn description(&self) -> &str { | |
342 | "asdf" | |
343 | } | |
344 | } | |
345 | ||
346 | // we have to call all of these UFCS style right now since method | |
347 | // resolution won't implicitly drop the Send+Sync bounds | |
348 | let mut err = Error::new(ErrorKind::Other, TestError); | |
c1a9b12d | 349 | assert!(err.get_ref().unwrap().is::<TestError>()); |
62682a34 | 350 | assert_eq!("asdf", err.get_ref().unwrap().description()); |
c1a9b12d | 351 | assert!(err.get_mut().unwrap().is::<TestError>()); |
62682a34 | 352 | let extracted = err.into_inner().unwrap(); |
c1a9b12d | 353 | extracted.downcast::<TestError>().unwrap(); |
62682a34 SL |
354 | } |
355 | } |