error_chain_mini/lib.rs
1//! This library provides very simple chainable error type `ChainedError` and some related traits.
2//! # Example
3//! ```
4//! extern crate error_chain_mini;
5//! #[macro_use]
6//! extern crate error_chain_mini_derive;
7//! use std::io;
8//! use error_chain_mini::*;
9//! #[derive(ErrorKind)]
10//! enum MyErrorKind {
11//! #[msg(short = "io error", detailed = "inner: {:?}", _0)]
12//! IoError(io::Error),
13//! #[msg(short = "index error", detailed = "invalid index: {:?}", _0)]
14//! IndexEroor(usize),
15//! #[msg(short = "trivial error")]
16//! TrivialError,
17//! }
18//! type MyError = ChainedError<MyErrorKind>;
19//! type MyResult<T> = Result<T, MyError>;
20//! fn always_fail() -> MyResult<()> {
21//! Err(MyErrorKind::TrivialError.into_with(|| "Oh my god!"))
22//! }
23//! fn main() {
24//! assert_eq!("index error { invalid index: 10 }", MyErrorKind::IndexEroor(10).full());
25//! let chained = always_fail().chain_err(|| "Error in main()");
26//! assert!(chained.is_err());
27//! if let Err(chained) = chained {
28//! let mut cxts = chained.contexts();
29//! assert_eq!(cxts.next().unwrap(), "Oh my god!");
30//! assert_eq!(cxts.next().unwrap(), "Error in main()");
31//! }
32//! }
33//! ```
34
35use std::error::Error;
36use std::fmt::{self, Debug, Display, Formatter};
37
38/// Error kind type.
39///
40/// You can implement `short`, which is exepected to return short hand description about error kind.
41///
42/// In addition, you can implement detailed description by `detailed`, but it's optional.
43/// # Example
44/// ```
45/// # extern crate error_chain_mini; fn main() {
46/// use std::io;
47/// use std::fs::File;
48/// use std::error::Error;
49/// use error_chain_mini::{ErrorKind, ResultExt};
50/// enum MyErrorKind {
51/// IoError(io::Error),
52/// IndexEroor(usize),
53/// }
54/// impl ErrorKind for MyErrorKind {
55/// fn short(&self) -> &str {
56/// match *self {
57/// MyErrorKind::IoError(_) => "io error",
58/// MyErrorKind::IndexEroor(_) => "index error"
59/// }
60/// }
61/// }
62/// impl From<io::Error> for MyErrorKind {
63/// fn from(e: io::Error) -> Self {
64/// MyErrorKind::IoError(e)
65/// }
66/// }
67/// let file = File::open("not_existing_file").into_chained(|| "In io()");
68/// assert!(file.is_err());
69/// if let Err(e) = file {
70/// assert_eq!(e.description(), "io error");
71/// if let MyErrorKind::IoError(ioerr) = e.kind() {
72/// assert_eq!(format!("{}", ioerr), "No such file or directory (os error 2)");
73/// } else {
74/// panic!("error kind is incorrect");
75/// }
76/// assert_eq!(e.contexts().collect::<Vec<_>>(), vec!["In io()"])
77/// }
78/// # }
79/// ```
80///
81/// Instead of implement `ErrorKind`, you can use derive.
82/// In this case, if you don't write `#[msg..` attribute, full path of the variant
83/// (e.g. `MyErrorKind::IndexError`) is used for the return value of `short`.
84///
85/// **Notes**
86/// If you derive `ErrorKind` for type A, `std::fmt::Display` is automatically implemented
87/// for convinience.
88///
89/// # Example
90/// ```
91/// # extern crate error_chain_mini;
92/// # #[macro_use] extern crate error_chain_mini_derive;
93/// # fn main() {
94/// use std::io;
95/// use std::fs::File;
96/// use std::error::Error;
97/// use error_chain_mini::{ErrorKind, ResultExt};
98/// #[derive(ErrorKind)]
99/// enum MyErrorKind {
100/// IoError(io::Error),
101/// IndexEroor(usize),
102/// }
103/// impl From<io::Error> for MyErrorKind {
104/// fn from(e: io::Error) -> Self {
105/// MyErrorKind::IoError(e)
106/// }
107/// }
108/// let file = File::open("not_existing_file").into_chained(|| "In io()");
109/// assert!(file.is_err());
110/// if let Err(e) = file {
111/// assert_eq!(e.description(), "MyErrorKind::IoError");
112/// assert_eq!(format!("{}", e.kind()), "MyErrorKind::IoError");
113/// if let MyErrorKind::IoError(ioerr) = e.kind() {
114/// assert_eq!(format!("{}", ioerr), "No such file or directory (os error 2)");
115/// } else {
116/// panic!("error kind is incorrect");
117/// }
118/// assert_eq!(e.contexts().collect::<Vec<_>>(), vec!["In io()"])
119/// }
120/// # }
121/// ```
122pub trait ErrorKind {
123 /// Short description of error type, compatible with `std::error::Error::description`.
124 ///
125 /// To avoid duplication of implement same message, we have 2 message type short/detailed.
126 ///
127 /// Actually, `"{}: {}", ErrorKind::short(), ErrorKind::detailed()"` is used for display
128 /// and you can also get full error message by `full` method.
129 fn short(&self) -> &str;
130
131 /// Detailed description of error type.
132 fn detailed(&self) -> String {
133 String::new()
134 }
135 /// Return full error message as String.
136 ///
137 /// **Notes** Do not overrride this method.
138 /// # Usage
139 /// ```
140 /// # extern crate error_chain_mini;
141 /// # #[macro_use] extern crate error_chain_mini_derive;
142 /// # fn main() {
143 /// use error_chain_mini::*;
144 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
145 /// #[msg(short = "My Error", detailed = "value: {}", value)]
146 /// struct MyError {
147 /// value: usize,
148 /// }
149 /// let err = MyError { value: 320 };
150 /// assert_eq!(format!("{}", err), err.full());
151 /// # }
152 /// ```
153 fn full(&self) -> String {
154 let detailed = self.detailed();
155 if detailed.is_empty() {
156 self.short().to_string()
157 } else {
158 format!("{} {{ {} }}", self.short(), self.detailed())
159 }
160 }
161
162 /// Get [ChainedError](struct.ChainedError.html) with no context.
163 ///
164 /// Do not overrride this method.
165 /// # Usage
166 /// ```
167 /// # extern crate error_chain_mini;
168 /// # #[macro_use] extern crate error_chain_mini_derive;
169 /// # use error_chain_mini::*; fn main() {
170 /// #[derive(Clone, Copy, ErrorKind, Eq, PartialEq, Debug)]
171 /// struct MyError;
172 /// let chained = MyError{}.into_err();
173 /// assert_eq!(*chained.kind(), MyError {});
174 /// # }
175 /// ```
176 fn into_err(self) -> ChainedError<Self>
177 where
178 Self: Sized,
179 {
180 ChainedError::new(self, vec![])
181 }
182
183 /// Get [ChainedError](struct.ChainedError.html) with a context.
184 ///
185 /// Do not overrride this method.
186 /// # Usage
187 /// ```
188 /// # extern crate error_chain_mini;
189 /// # #[macro_use] extern crate error_chain_mini_derive;
190 /// # use error_chain_mini::*; fn main() {
191 /// fn my_func() {
192 /// #[derive(Clone, Copy, ErrorKind, Eq, PartialEq, Debug)]
193 /// struct MyError;
194 /// let chained = MyError{}.into_with(|| "Error in my_func");
195 /// assert_eq!(*chained.kind(), MyError {});
196 /// assert_eq!(chained.contexts().nth(0).unwrap(), "Error in my_func");
197 /// }
198 /// # }
199 /// ```
200 fn into_with<C: ErrorContext, F>(self, op: F) -> ChainedError<Self>
201 where
202 F: FnOnce() -> C,
203 Self: Sized,
204 {
205 ChainedError::new(self, vec![Box::new(op())])
206 }
207}
208
209/// Error context type.
210///
211/// Expected usage is use string as context.
212///
213/// See module level documentation for usage.
214pub trait ErrorContext: 'static {
215 fn context(&self) -> &str;
216}
217
218impl<S: 'static + AsRef<str>> ErrorContext for S {
219 fn context(&self) -> &str {
220 self.as_ref()
221 }
222}
223
224/// Chainable error type.
225///
226/// See module level documentation for usage.
227pub struct ChainedError<T: ErrorKind> {
228 inner: Box<ErrorImpl<T>>,
229}
230
231impl<T: ErrorKind> Debug for ChainedError<T> {
232 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
233 Display::fmt(self, f)
234 }
235}
236
237impl<T: ErrorKind> Error for ChainedError<T> {
238 fn description(&self) -> &str {
239 self.inner.kind.short()
240 }
241}
242
243impl<T: ErrorKind> Display for ChainedError<T> {
244 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
245 write!(f, "\nkind: {}", self.inner.kind.short())?;
246 let detailed = self.inner.kind.detailed();
247 if !detailed.is_empty() {
248 write!(f, " {{ {} }}", detailed)?;
249 }
250 writeln!(f)?;
251 for (i, s) in self.inner.context.iter().enumerate() {
252 if i != 0 {
253 writeln!(f)?;
254 }
255 write!(f, "context{:3}: {}", i, s.context())?;
256 }
257 writeln!(f)
258 }
259}
260
261impl<T: ErrorKind> ChainedError<T> {
262 /// Create new ChainedError.
263 pub fn new(kind: T, context: Vec<Box<ErrorContext>>) -> Self {
264 ChainedError {
265 inner: Box::new(ErrorImpl::new(kind, context)),
266 }
267 }
268
269 /// Returns a reference of Error Kind
270 /// # Usage
271 /// ```
272 /// # extern crate error_chain_mini;
273 /// # #[macro_use] extern crate error_chain_mini_derive;
274 /// # use error_chain_mini::*;
275 /// # fn main() {
276 /// #[derive(Debug, ErrorKind, Eq, PartialEq)]
277 /// enum ErrorType {
278 /// A,
279 /// B,
280 /// C
281 /// }
282 /// let chained = ErrorType::B.into_err();
283 /// assert_eq!(*chained.kind(), ErrorType::B);
284 /// # }
285 /// ```
286 pub fn kind(&self) -> &T {
287 &self.inner.kind
288 }
289
290 /// Returns a reference of Error Contexts
291 /// Returns a reference of Error Kind
292 /// # Usage
293 /// ```
294 /// # extern crate error_chain_mini;
295 /// # #[macro_use] extern crate error_chain_mini_derive;
296 /// # use error_chain_mini::*;
297 /// # fn main() {
298 /// #[derive(Debug, ErrorKind, Eq, PartialEq)]
299 /// enum ErrorType {
300 /// A,
301 /// B,
302 /// C
303 /// }
304 /// let chained = ErrorType::B.into_with(|| "Error is Caused!");
305 /// let chained = chained.chain(|| "Error is Chained!");
306 /// let mut cxts = chained.contexts();
307 /// assert_eq!(cxts.next().unwrap(), "Error is Caused!");
308 /// assert_eq!(cxts.next().unwrap(), "Error is Chained!");
309 /// # }
310 /// ```
311 pub fn contexts(&self) -> impl Iterator<Item = &str> {
312 self.inner.context.iter().map(|cxt| cxt.context())
313 }
314
315 /// Add context to ChainedError by closure.
316 ///
317 /// It's more useful to use [chain_err](trait.ResultExt.html#tymethod.chain_err).
318 pub fn chain<C, F>(mut self, op: F) -> Self
319 where
320 C: ErrorContext,
321 F: FnOnce() -> C,
322 {
323 self.inner.context.push(Box::new(op()));
324 self
325 }
326
327 /// Convert `ChainedError<T>` into `ChainedError<U>` using `std::convert::from`.
328 ///
329 /// # Usage
330 ///
331 /// ```
332 /// # extern crate error_chain_mini;
333 /// # #[macro_use] extern crate error_chain_mini_derive;
334 /// # use error_chain_mini::*;
335 /// mod external {
336 /// # use super::*;
337 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
338 /// #[msg(short = "error in external")]
339 /// pub struct ExtErrorKind;
340 /// pub type Error = ChainedError<ExtErrorKind>;
341 /// pub fn func() -> Result<(), Error> {
342 /// Err(ExtErrorKind{}.into_with(|| "In external::func()"))
343 /// }
344 /// }
345 /// # fn main() {
346 /// use external::{self, ExtErrorKind};
347 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
348 /// enum MyErrorKind {
349 /// Internal,
350 /// #[msg(short = "from mod 'external'", detailed = "{:?}", _0)]
351 /// External(ExtErrorKind),
352 /// };
353 /// impl From<ExtErrorKind> for MyErrorKind {
354 /// fn from(e: ExtErrorKind) -> MyErrorKind {
355 /// MyErrorKind::External(e)
356 /// }
357 /// }
358 /// type Error = ChainedError<MyErrorKind>;
359 /// let chained: Result<(), Error>
360 /// = external::func().map_err(|e| e.convert().chain(|| "In my_func()"));
361 /// if let Err(chained) = chained {
362 /// assert_eq!(*chained.kind(), MyErrorKind::External(ExtErrorKind {}));
363 /// assert_eq!(chained.contexts().nth(1).unwrap(), "In my_func()");
364 /// }
365 /// # }
366 /// ```
367 pub fn convert<U>(self) -> ChainedError<U>
368 where
369 U: ErrorKind + From<T>,
370 {
371 ChainedError {
372 inner: Box::new(self.inner.convert(U::from)),
373 }
374 }
375
376 /// Convert `ChainedError<T>` into `ChainedError<U>` using closure.
377 ///
378 /// # Usage
379 ///
380 /// ```
381 /// # extern crate error_chain_mini;
382 /// # #[macro_use] extern crate error_chain_mini_derive;
383 /// # use error_chain_mini::*;
384 /// mod external {
385 /// # use super::*;
386 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
387 /// #[msg(short = "error in external")]
388 /// pub struct ExtErrorKind;
389 /// pub type Error = ChainedError<ExtErrorKind>;
390 /// pub fn func() -> Result<(), Error> {
391 /// Err(ExtErrorKind{}.into_with(|| "In external::func()"))
392 /// }
393 /// }
394 /// # fn main() {
395 /// use external::{self, ExtErrorKind};
396 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
397 /// enum MyErrorKind {
398 /// Internal,
399 /// #[msg(short = "from mod 'external'", detailed = "{:?}", _0)]
400 /// External(ExtErrorKind),
401 /// };
402 /// type Error = ChainedError<MyErrorKind>;
403 /// let chained: Result<(), Error> = external::func().map_err(|e| {
404 /// e.convert_with(|e| MyErrorKind::External(e))
405 /// .chain(|| "In my_func()")
406 /// });
407 /// if let Err(chained) = chained {
408 /// assert_eq!(*chained.kind(), MyErrorKind::External(ExtErrorKind {}));
409 /// assert_eq!(chained.contexts().nth(1).unwrap(), "In my_func()");
410 /// }
411 /// # }
412 /// ```
413 pub fn convert_with<U, F>(self, converter: F) -> ChainedError<U>
414 where
415 U: ErrorKind,
416 F: FnOnce(T) -> U,
417 {
418 ChainedError {
419 inner: Box::new(self.inner.convert(converter)),
420 }
421 }
422}
423
424struct ErrorImpl<T> {
425 kind: T,
426 context: Vec<Box<ErrorContext>>,
427}
428
429impl<T> ErrorImpl<T> {
430 fn new(kind: T, context: Vec<Box<ErrorContext>>) -> Self {
431 ErrorImpl { kind, context }
432 }
433 fn convert<F, U>(self, f: F) -> ErrorImpl<U>
434 where
435 F: FnOnce(T) -> U,
436 {
437 ErrorImpl::new(f(self.kind), self.context)
438 }
439}
440
441unsafe impl<T: ErrorKind + Sync> Sync for ErrorImpl<T> {}
442unsafe impl<T: ErrorKind + Send> Send for ErrorImpl<T> {}
443
444/// `Result` extension to integrate with `ChainedError`
445pub trait ResultExt {
446 type OkType;
447 type ErrType;
448 /// Almost same as `chain_err`, but takes closure.
449 /// If you want to do expensive operation like `format!` to generate error message,
450 /// use this method instead of `chain_err`.
451 /// # Usage
452 /// ```
453 /// # extern crate error_chain_mini;
454 /// # #[macro_use] extern crate error_chain_mini_derive;
455 /// # fn main() {
456 /// use error_chain_mini::*;
457 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
458 /// #[msg(short = "My Error")]
459 /// struct MyError;
460 /// fn my_func() -> Result<(), ChainedError<MyError>>{
461 /// let chained = MyError{}.into_with(|| "Error in my_func");
462 /// Err(chained)
463 /// }
464 /// let chained = my_func().chain_err(|| "Chained");
465 /// assert!(chained.is_err());
466 /// if let Err(e) = chained {
467 /// let msg = format!("{}", e);
468 /// assert_eq!(msg, r#"
469 /// kind: My Error
470 /// context 0: Error in my_func
471 /// context 1: Chained
472 /// "#);
473 /// }
474 /// # }
475 /// ```
476 fn chain_err<C, K, F>(self, op: F) -> Result<Self::OkType, ChainedError<K>>
477 where
478 F: FnOnce() -> C,
479 K: ErrorKind,
480 C: ErrorContext,
481 Self::ErrType: Into<ChainedError<K>>;
482
483 /// Takes Result and context then convert its error type into `ChainedError` with context.
484 /// # Usage
485 /// ```
486 /// # extern crate error_chain_mini;
487 /// # #[macro_use] extern crate error_chain_mini_derive;
488 /// # fn main() {
489 /// use error_chain_mini::*;
490 /// use std::io;
491 /// use std::fs::File;
492 /// #[derive(Debug, ErrorKind)]
493 /// enum MyError {
494 /// #[msg(short = "io error", detailed = "{:?}", _0)]
495 /// Io(io::Error),
496 /// Misc
497 /// }
498 /// impl From<io::Error> for MyError {
499 /// fn from(e: io::Error) -> Self {
500 /// MyError::Io(e)
501 /// }
502 /// }
503 /// let file: Result<_, ChainedError<MyError>> = File::open("not_existing_file").into_chained(|| "In io()");
504 /// # }
505 /// ```
506 fn into_chained<C, K, F>(self, op: F) -> Result<Self::OkType, ChainedError<K>>
507 where
508 F: FnOnce() -> C,
509 K: ErrorKind + From<Self::ErrType>,
510 C: ErrorContext;
511
512 /// Convert `Result<Ok, ChainedError<T>>` into `Result<Ok, ChainedError<U>>` using `std::convert::From`.
513 ///
514 /// # Usage
515 ///
516 /// ```
517 /// # extern crate error_chain_mini;
518 /// # #[macro_use] extern crate error_chain_mini_derive;
519 /// # use error_chain_mini::*;
520 /// mod external {
521 /// # use super::*;
522 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
523 /// #[msg(short = "error in external")]
524 /// pub struct ExtErrorKind;
525 /// pub type Error = ChainedError<ExtErrorKind>;
526 /// pub fn func() -> Result<(), Error> {
527 /// Err(ExtErrorKind{}.into_with(|| "In external::func()"))
528 /// }
529 /// }
530 /// # fn main() {
531 /// use external::{self, ExtErrorKind};
532 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
533 /// enum MyErrorKind {
534 /// Internal,
535 /// #[msg(short = "from mod 'external'", detailed = "{:?}", _0)]
536 /// External(ExtErrorKind),
537 /// };
538 /// impl From<ExtErrorKind> for MyErrorKind {
539 /// fn from(e: ExtErrorKind) -> MyErrorKind {
540 /// MyErrorKind::External(e)
541 /// }
542 /// }
543 /// type Error = ChainedError<MyErrorKind>;
544 /// let chained: Result<(), Error> = external::func().convert();
545 /// if let Err(chained) = chained {
546 /// assert_eq!(*chained.kind(), MyErrorKind::External(ExtErrorKind {}));
547 /// }
548 /// # }
549 /// ```
550 fn convert<K, U>(self) -> Result<Self::OkType, ChainedError<U>>
551 where
552 K: ErrorKind,
553 Self::ErrType: Into<ChainedError<K>>,
554 U: From<K> + ErrorKind;
555
556 /// Convert `Result<Ok, ChainedError<T>>` into `Result<Ok, ChainedError<U>>` using closure.
557 ///
558 /// # Usage
559 ///
560 /// ```
561 /// # extern crate error_chain_mini;
562 /// # #[macro_use] extern crate error_chain_mini_derive;
563 /// # use error_chain_mini::*;
564 /// mod external {
565 /// # use super::*;
566 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
567 /// #[msg(short = "error in external")]
568 /// pub struct ExtErrorKind;
569 /// pub type Error = ChainedError<ExtErrorKind>;
570 /// pub fn func() -> Result<(), Error> {
571 /// Err(ExtErrorKind{}.into_with(|| "In external::func()"))
572 /// }
573 /// }
574 /// # fn main() {
575 /// use external::{self, ExtErrorKind};
576 /// #[derive(ErrorKind, Eq, PartialEq, Debug)]
577 /// enum MyErrorKind {
578 /// Internal,
579 /// #[msg(short = "from mod 'external'", detailed = "{:?}", _0)]
580 /// External(ExtErrorKind),
581 /// };
582 /// type Error = ChainedError<MyErrorKind>;
583 /// let chained: Result<(), Error>
584 /// = external::func().convert_with(|e| MyErrorKind::External(e));
585 /// if let Err(chained) = chained {
586 /// assert_eq!(*chained.kind(), MyErrorKind::External(ExtErrorKind {}));
587 /// }
588 /// # }
589 /// ```
590 fn convert_with<K, U, F>(self, converter: F) -> Result<Self::OkType, ChainedError<U>>
591 where
592 K: ErrorKind,
593 Self::ErrType: Into<ChainedError<K>>,
594 U: ErrorKind,
595 F: FnOnce(K) -> U;
596}
597
598impl<T, E> ResultExt for Result<T, E> {
599 type OkType = T;
600 type ErrType = E;
601
602 fn chain_err<C, K, F>(self, op: F) -> Result<Self::OkType, ChainedError<K>>
603 where
604 F: FnOnce() -> C,
605 K: ErrorKind,
606 C: ErrorContext,
607 Self::ErrType: Into<ChainedError<K>>,
608 {
609 self.map_err(|e| e.into().chain(op))
610 }
611
612 fn into_chained<C, K, F>(self, op: F) -> Result<Self::OkType, ChainedError<K>>
613 where
614 F: FnOnce() -> C,
615 K: ErrorKind + From<Self::ErrType>,
616 C: ErrorContext,
617 {
618 self.map_err(|e| K::from(e).into_with(op))
619 }
620
621 fn convert<K, U>(self) -> Result<Self::OkType, ChainedError<U>>
622 where
623 K: ErrorKind,
624 Self::ErrType: Into<ChainedError<K>>,
625 U: From<K> + ErrorKind,
626 {
627 self.map_err(|e| e.into().convert())
628 }
629
630 fn convert_with<K, U, F>(self, converter: F) -> Result<Self::OkType, ChainedError<U>>
631 where
632 K: ErrorKind,
633 Self::ErrType: Into<ChainedError<K>>,
634 U: ErrorKind,
635 F: FnOnce(K) -> U,
636 {
637 self.map_err(|e| e.into().convert_with(converter))
638 }
639}
640
641#[cfg(test)]
642mod test {
643 use super::*;
644 use std::io::Error as IoError;
645 enum MyErrorKind {
646 Io(IoError),
647 Index(usize),
648 }
649 impl ErrorKind for MyErrorKind {
650 fn short(&self) -> &str {
651 match self {
652 MyErrorKind::Io(_) => "io error",
653 MyErrorKind::Index(_) => "index error",
654 }
655 }
656 fn detailed(&self) -> String {
657 match *self {
658 MyErrorKind::Io(ref io) => format!("{:?}", io),
659 MyErrorKind::Index(id) => format!("{}", id),
660 }
661 }
662 }
663 type MyError = ChainedError<MyErrorKind>;
664 impl From<IoError> for MyErrorKind {
665 fn from(e: IoError) -> Self {
666 MyErrorKind::Io(e)
667 }
668 }
669 fn index_err(u: usize) -> Result<u32, MyError> {
670 let array = vec![3, 7, 9, 20];
671 if let Some(u) = array.get(u) {
672 Ok(*u)
673 } else {
674 Err(MyErrorKind::Index(u).into_with(|| "Invalid access in index_err()"))
675 }
676 }
677 #[test]
678 fn io() {
679 use std::fs::File;
680 let file = File::open("not_existing_file").into_chained(|| "In io()");
681 assert!(file.is_err());
682 if let Err(e) = file {
683 if let MyErrorKind::Index(_) = e.kind() {
684 panic!("error kind is incorrect");
685 }
686 assert_eq!(e.contexts().collect::<Vec<_>>(), vec!["In io()"])
687 }
688 }
689 #[test]
690 fn index() {
691 let id = 8;
692 let res = index_err(id).chain_err(|| "In index()");
693 assert!(res.is_err());
694 if let Err(e) = res {
695 if let MyErrorKind::Index(u) = e.kind() {
696 assert_eq!(*u, id);
697 } else {
698 panic!("error kind is incorrect");
699 }
700 assert_eq!(
701 e.contexts().collect::<Vec<_>>(),
702 vec![
703 "Invalid access in index_err()".to_owned(),
704 "In index()".to_owned(),
705 ]
706 );
707 }
708 }
709 #[test]
710 #[should_panic]
711 fn display() {
712 let id = 8;
713 let res = index_err(id).chain_err(|| "In index()");
714 res.unwrap();
715 }
716}