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}