diff --git a/booksrc/SUMMARY.md b/booksrc/SUMMARY.md index 367577f..9c8d13a 100644 --- a/booksrc/SUMMARY.md +++ b/booksrc/SUMMARY.md @@ -14,5 +14,6 @@ - [ErrorKind to the rescue](tutorial10.md) - [Debug for the ErrorKind](tutorial11.md) - [Deref for the ErrorKind](tutorial12.md) +- [Writing a library](tutorial13.md) [The End](end.md) \ No newline at end of file diff --git a/booksrc/tutorial13.md b/booksrc/tutorial13.md new file mode 100644 index 0000000..2b3dde2 --- /dev/null +++ b/booksrc/tutorial13.md @@ -0,0 +1,18 @@ +# Writing a library + +I would advise to only expose an `mycrate::ErrorKind` and type alias `mycrate::Error` to `ChainError` +so you can tell your library users to use the `.kind()` method as `std::io::Error` does. + +If you later decide to make your own `Error` implementation, your library users don't +have to change much or anything. + +~~~rust +# #[allow(dead_code)] +# #[macro_use] +# pub mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +pub mod mycrate { + use crate::chainerror::*; // omit the `crate::` part +{{#include ../examples/tutorial13.rs:3:}} +~~~ diff --git a/examples/tutorial13.rs b/examples/tutorial13.rs new file mode 100644 index 0000000..fdc0939 --- /dev/null +++ b/examples/tutorial13.rs @@ -0,0 +1,76 @@ +pub mod mycrate { + use chainerror::*; + use std::io; + + fn do_some_io() -> std::result::Result<(), Box> { + Err(io::Error::from(io::ErrorKind::NotFound))?; + Ok(()) + } + + derive_str_cherr!(Func2Error); + + fn func2() -> std::result::Result<(), Box> { + let filename = "foo.txt"; + do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; + Ok(()) + } + + #[derive(Debug)] + pub enum ErrorKind { + Func2, + IO(String), + } + + pub type Error = ChainError; + pub type Result = std::result::Result; + + impl ::std::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + ErrorKind::Func2 => write!(f, "func1 error calling func2"), + ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename), + } + } + } + + pub fn func1() -> Result<()> { + func2().map_err(|e| cherr!(e, ErrorKind::Func2))?; + let filename = String::from("bar.txt"); + do_some_io().map_err(|e| cherr!(e, ErrorKind::IO(filename)))?; + Ok(()) + } +} + +fn main() -> Result<(), Box> { + use mycrate::func1; + use mycrate::ErrorKind; + use std::error::Error; + use std::io; + + if let Err(e) = func1() { + match e.kind() { + ErrorKind::Func2 => eprintln!("Main Error Report: func1 error calling func2"), + ErrorKind::IO(ref filename) => { + eprintln!("Main Error Report: func1 error reading '{}'", filename) + } + } + + eprintln!(); + let mut s : &Error = &e; + while let Some(c) = s.source() { + if let Some(ioerror) = c.downcast_ref::() { + eprintln!("caused by: std::io::Error: {}", ioerror); + match ioerror.kind() { + io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"), + _ => {} + } + } else { + eprintln!("caused by: {}", c); + } + s = c; + } + + eprintln!("\nDebug Error:\n{:?}", e); + } + Ok(()) +}