mirror of
				https://github.com/haraldh/chainerror.git
				synced 2025-11-04 08:18:08 +01:00 
			
		
		
		
	add tutorial
This commit is contained in:
		
							parent
							
								
									d1295092a4
								
							
						
					
					
						commit
						46e2c78aa8
					
				
					 13 changed files with 594 additions and 298 deletions
				
			
		| 
						 | 
				
			
			@ -1,169 +0,0 @@
 | 
			
		|||
use std::error::Error;
 | 
			
		||||
use std::io::Error as IoError;
 | 
			
		||||
use std::io::ErrorKind as IoErrorKind;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq, Debug)]
 | 
			
		||||
enum ParseError {
 | 
			
		||||
    InvalidValue(u32),
 | 
			
		||||
    InvalidParameter(String),
 | 
			
		||||
    NoOpen,
 | 
			
		||||
    NoClose,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ::std::fmt::Display for ParseError {
 | 
			
		||||
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            ParseError::InvalidValue(a) => write!(f, "InvalidValue: {}", a),
 | 
			
		||||
            ParseError::InvalidParameter(a) => write!(f, "InvalidParameter: '{}'", a),
 | 
			
		||||
            ParseError::NoOpen => write!(f, "No opening '{{' in config file"),
 | 
			
		||||
            ParseError::NoClose => write!(f, "No closing '}}' in config file"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn parse_config(c: String) -> Result<(), Box<Error>> {
 | 
			
		||||
    if !c.starts_with('{') {
 | 
			
		||||
        Err(cherr!(ParseError::NoOpen))?;
 | 
			
		||||
    }
 | 
			
		||||
    if !c.ends_with('}') {
 | 
			
		||||
        Err(cherr!(ParseError::NoClose))?;
 | 
			
		||||
    }
 | 
			
		||||
    let c = &c[1..(c.len() - 1)];
 | 
			
		||||
    let v = c
 | 
			
		||||
        .parse::<u32>()
 | 
			
		||||
        .map_err(|e| cherr!(e, ParseError::InvalidParameter(c.into())))?;
 | 
			
		||||
    if v > 100 {
 | 
			
		||||
        Err(cherr!(ParseError::InvalidValue(v)))?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(ConfigFileError);
 | 
			
		||||
derive_str_cherr!(SeriousError);
 | 
			
		||||
derive_str_cherr!(FileError);
 | 
			
		||||
derive_str_cherr!(AppError);
 | 
			
		||||
 | 
			
		||||
fn file_reader(_filename: &Path) -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(IoError::from(IoErrorKind::NotFound)).map_err(mstrerr!(FileError, "File reader error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn read_config(filename: &Path) -> Result<(), Box<Error>> {
 | 
			
		||||
    if filename.eq(Path::new("global.ini")) {
 | 
			
		||||
        // assume we got an IO error
 | 
			
		||||
        file_reader(filename).map_err(mstrerr!(
 | 
			
		||||
            ConfigFileError,
 | 
			
		||||
            "Error reading file {:?}",
 | 
			
		||||
            filename
 | 
			
		||||
        ))?;
 | 
			
		||||
    }
 | 
			
		||||
    // assume we read some buffer
 | 
			
		||||
    if filename.eq(Path::new("local.ini")) {
 | 
			
		||||
        let buf = String::from("{1000}");
 | 
			
		||||
        parse_config(buf)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if filename.eq(Path::new("user.ini")) {
 | 
			
		||||
        let buf = String::from("foo");
 | 
			
		||||
        parse_config(buf)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if filename.eq(Path::new("user2.ini")) {
 | 
			
		||||
        let buf = String::from("{foo");
 | 
			
		||||
        parse_config(buf)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if filename.eq(Path::new("user3.ini")) {
 | 
			
		||||
        let buf = String::from("{foo}");
 | 
			
		||||
        parse_config(buf)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if filename.eq(Path::new("custom.ini")) {
 | 
			
		||||
        let buf = String::from("{10}");
 | 
			
		||||
        parse_config(buf)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if filename.eq(Path::new("essential.ini")) {
 | 
			
		||||
        Err(cherr!(SeriousError("Something is really wrong".into())))?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn read_verbose_config(p: &str) -> Result<(), Box<Error>> {
 | 
			
		||||
    eprintln!("Reading '{}' ... ", p);
 | 
			
		||||
    read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
 | 
			
		||||
    eprintln!("Ok reading {}", p);
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn start_app(debug: bool) -> Result<(), Box<Error>> {
 | 
			
		||||
    for p in &[
 | 
			
		||||
        "global.ini",
 | 
			
		||||
        "local.ini",
 | 
			
		||||
        "user.ini",
 | 
			
		||||
        "user2.ini",
 | 
			
		||||
        "user3.ini",
 | 
			
		||||
        "custom.ini",
 | 
			
		||||
        "essential.ini",
 | 
			
		||||
    ] {
 | 
			
		||||
        if let Err(e) = read_verbose_config(p) {
 | 
			
		||||
            assert!(e.is_chain::<AppError>());
 | 
			
		||||
            let app_err = e.downcast_chain_ref::<AppError>().unwrap();
 | 
			
		||||
 | 
			
		||||
            if app_err.find_kind::<SeriousError>().is_some() {
 | 
			
		||||
                // Bail out on SeriousError
 | 
			
		||||
                eprintln!("---> Serious Error:\n{:?}", e);
 | 
			
		||||
                Err(cherr!(e, AppError("Seriously".into())))?;
 | 
			
		||||
            } else if let Some(cfg_error) = app_err.find_kind::<ConfigFileError>() {
 | 
			
		||||
                if debug {
 | 
			
		||||
                    eprintln!("{:?}\n", cfg_error);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Deep Error handling
 | 
			
		||||
                    if let Some(chioerror) = cfg_error.find_kind::<IoError>() {
 | 
			
		||||
                        let ioerror = chioerror.kind();
 | 
			
		||||
                        match ioerror.kind() {
 | 
			
		||||
                            IoErrorKind::NotFound => {
 | 
			
		||||
                                eprint!("Ignoring missing file");
 | 
			
		||||
                                if let Some(root_cause) = cfg_error.root_cause() {
 | 
			
		||||
                                    eprint!(", because of: {}\n", root_cause);
 | 
			
		||||
                                }
 | 
			
		||||
                                eprintln!();
 | 
			
		||||
                            }
 | 
			
		||||
                            _ => Err(cherr!(e, AppError("Unhandled IOError".into())))?,
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        eprintln!("ConfigFileError for: {}", e);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if debug {
 | 
			
		||||
                    eprintln!("Error reading:\n{:?}\n", e)
 | 
			
		||||
                } else {
 | 
			
		||||
                    eprintln!("Error reading: {}\n", e)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        eprintln!();
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    eprintln!("Display:\n");
 | 
			
		||||
    let e = start_app(false).unwrap_err();
 | 
			
		||||
    assert!(e.is_chain::<AppError>());
 | 
			
		||||
    eprintln!("\n\n==================================");
 | 
			
		||||
    eprintln!("====    Debug output");
 | 
			
		||||
    eprintln!("==================================\n");
 | 
			
		||||
    let r = start_app(true);
 | 
			
		||||
 | 
			
		||||
    eprintln!("\n\n==================================");
 | 
			
		||||
    eprintln!("====    Main return output");
 | 
			
		||||
    eprintln!("==================================\n");
 | 
			
		||||
    r
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								examples/tutorial1.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								examples/tutorial1.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial1
 | 
			
		||||
Error: StringError("func1 error")
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err("do_some_io error")?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(_) = do_some_io() {
 | 
			
		||||
        Err("func2 error")?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(_) = func2() {
 | 
			
		||||
        Err("func1 error")?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    func1()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								examples/tutorial10.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								examples/tutorial10.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial10
 | 
			
		||||
Main Error Report: func1 error calling func2
 | 
			
		||||
Error reported by Func2Error: Error reading 'foo.txt'
 | 
			
		||||
 | 
			
		||||
Debug Error:
 | 
			
		||||
examples/tutorial10.rs:49: Func2
 | 
			
		||||
Caused by:
 | 
			
		||||
examples/tutorial10.rs:29: Func2Error(Error reading 'foo.txt')
 | 
			
		||||
Caused by:
 | 
			
		||||
Kind(NotFound)
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(Func2Error);
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum Func1Error {
 | 
			
		||||
    Func2,
 | 
			
		||||
    IO(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ::std::fmt::Display for Func1Error {
 | 
			
		||||
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Func1Error::Func2 => write!(f, "func1 error calling func2"),
 | 
			
		||||
            Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> ChainResult<(), Func1Error> {
 | 
			
		||||
    func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
 | 
			
		||||
    let filename = String::from("bar.txt");
 | 
			
		||||
    do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        match e.kind() {
 | 
			
		||||
            Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
 | 
			
		||||
            Func1Error::IO(filename) => {
 | 
			
		||||
                eprintln!("Main Error Report: func1 error reading '{}'", filename)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(e) = e.find_chain_cause::<Func2Error>() {
 | 
			
		||||
            eprintln!("Error reported by Func2Error: {}", e)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        eprintln!("\nDebug Error:\n{:?}", e);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								examples/tutorial11.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								examples/tutorial11.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial11
 | 
			
		||||
Main Error Report: func1 error calling func2
 | 
			
		||||
Error reported by Func2Error: Error reading 'foo.txt'
 | 
			
		||||
 | 
			
		||||
Debug Error:
 | 
			
		||||
examples/tutorial11.rs:57: func1 error calling func2
 | 
			
		||||
Caused by:
 | 
			
		||||
examples/tutorial11.rs:32: Func2Error(Error reading 'foo.txt')
 | 
			
		||||
Caused by:
 | 
			
		||||
Kind(NotFound)
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(Func2Error);
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum Func1Error {
 | 
			
		||||
    Func2,
 | 
			
		||||
    IO(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ::std::fmt::Display for Func1Error {
 | 
			
		||||
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Func1Error::Func2 => write!(f, "func1 error calling func2"),
 | 
			
		||||
            Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ::std::fmt::Debug for Func1Error {
 | 
			
		||||
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
 | 
			
		||||
        write!(f, "{}", self)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> ChainResult<(), Func1Error> {
 | 
			
		||||
    func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
 | 
			
		||||
    let filename = String::from("bar.txt");
 | 
			
		||||
    do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        match e.kind() {
 | 
			
		||||
            Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
 | 
			
		||||
            Func1Error::IO(filename) => {
 | 
			
		||||
                eprintln!("Main Error Report: func1 error reading '{}'", filename)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(e) = e.find_chain_cause::<Func2Error>() {
 | 
			
		||||
            eprintln!("Error reported by Func2Error: {}", e)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        eprintln!("\nDebug Error:\n{:?}", e);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								examples/tutorial2.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								examples/tutorial2.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial2
 | 
			
		||||
Error: examples/tutorial2.rs:28: "func1 error"
 | 
			
		||||
Caused by:
 | 
			
		||||
examples/tutorial2.rs:21: "func2 error"
 | 
			
		||||
Caused by:
 | 
			
		||||
StringError("do_some_io error")
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err("do_some_io error")?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = do_some_io() {
 | 
			
		||||
        Err(cherr!(e, "func2 error"))?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func2() {
 | 
			
		||||
        Err(cherr!(e, "func1 error"))?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    func1()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								examples/tutorial3.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/tutorial3.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial3
 | 
			
		||||
examples/tutorial3.rs:30: "func1 error"
 | 
			
		||||
Caused by:
 | 
			
		||||
examples/tutorial3.rs:25: "func2 error"
 | 
			
		||||
Caused by:
 | 
			
		||||
StringError("do_some_io error")
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err("do_some_io error")?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    do_some_io().map_err(|e| cherr!(e, "func2 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    func2().map_err(|e| cherr!(e, "func1 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        eprintln!("{:?}", e);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								examples/tutorial4.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/tutorial4.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial4
 | 
			
		||||
examples/tutorial4.rs:29: "func1 error"
 | 
			
		||||
Caused by:
 | 
			
		||||
examples/tutorial4.rs:24: "func2 error"
 | 
			
		||||
Caused by:
 | 
			
		||||
StringError("do_some_io error")
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err("do_some_io error")?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    do_some_io().map_err(mstrerr!("func2 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    func2().map_err(mstrerr!("func1 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        eprintln!("{:?}", e);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								examples/tutorial5.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								examples/tutorial5.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial5
 | 
			
		||||
Func2 failed because of 'entity not found'
 | 
			
		||||
func1 error
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func2() {
 | 
			
		||||
        if let Some(s) = e.source() {
 | 
			
		||||
            eprintln!("func2 failed because of '{}'", s);
 | 
			
		||||
            Err(e).map_err(mstrerr!("func1 error"))?;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        eprintln!("{}", e);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								examples/tutorial6.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								examples/tutorial6.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial6
 | 
			
		||||
Error: func1 error
 | 
			
		||||
caused by: Error reading 'foo.txt'
 | 
			
		||||
caused by: std::io::Error: entity not found
 | 
			
		||||
of kind: std::io::ErrorKind::NotFound
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    func2().map_err(mstrerr!("func1 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        eprintln!("Error: {}", e);
 | 
			
		||||
        let mut s = e.as_ref();
 | 
			
		||||
        while let Some(c) = s.source() {
 | 
			
		||||
            if let Some(ioerror) = c.downcast_ref::<io::Error>() {
 | 
			
		||||
                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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								examples/tutorial7.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								examples/tutorial7.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial7
 | 
			
		||||
Error: func1 error
 | 
			
		||||
caused by: std::io::Error: entity not found
 | 
			
		||||
of kind: std::io::ErrorKind::NotFound
 | 
			
		||||
The root cause was: std::io::Error: Kind(
 | 
			
		||||
    NotFound
 | 
			
		||||
)
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    func2().map_err(mstrerr!("func1 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        eprintln!("Error: {}", e);
 | 
			
		||||
        if let Some(s) = e.downcast_chain_ref::<String>() {
 | 
			
		||||
            if let Some(ioerror) = s.find_cause::<io::Error>() {
 | 
			
		||||
                eprintln!("caused by: std::io::Error: {}", ioerror);
 | 
			
		||||
                match ioerror.kind() {
 | 
			
		||||
                    io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"),
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if let Some(e) = s.root_cause() {
 | 
			
		||||
                let ioerror = e.downcast_ref::<io::Error>().unwrap();
 | 
			
		||||
                eprintln!("The root cause was: std::io::Error: {:#?}", ioerror);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								examples/tutorial8.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								examples/tutorial8.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial8
 | 
			
		||||
Func1Error: func1 error
 | 
			
		||||
Func2Error: Error reading 'foo.txt'
 | 
			
		||||
Debug Func2Error:
 | 
			
		||||
examples/tutorial8.rs:27: Func2Error(Error reading 'foo.txt')
 | 
			
		||||
Caused by:
 | 
			
		||||
Kind(NotFound)
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(Func2Error);
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(Func1Error);
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
 | 
			
		||||
            eprintln!("Func1Error: {}", f1err);
 | 
			
		||||
 | 
			
		||||
            if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() {
 | 
			
		||||
                eprintln!("Func2Error: {}", f2err);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if let Some(f2err) = f1err.find_chain_cause::<Func2Error>() {
 | 
			
		||||
                eprintln!("Debug Func2Error:\n{:?}", f2err);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								examples/tutorial9.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								examples/tutorial9.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
/*!
 | 
			
		||||
 | 
			
		||||
~~~bash
 | 
			
		||||
$ cargo run -q --example tutorial9
 | 
			
		||||
Func1ErrorFunc2:
 | 
			
		||||
examples/tutorial9.rs:37: Func1ErrorFunc2(func1 error calling func2)
 | 
			
		||||
Caused by:
 | 
			
		||||
examples/tutorial9.rs:29: Func2Error(Error reading 'foo.txt')
 | 
			
		||||
Caused by:
 | 
			
		||||
Kind(NotFound)
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
!*/
 | 
			
		||||
 | 
			
		||||
use chainerror::prelude::*;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
 | 
			
		||||
fn do_some_io() -> Result<(), Box<Error>> {
 | 
			
		||||
    Err(io::Error::from(io::ErrorKind::NotFound))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(Func2Error);
 | 
			
		||||
 | 
			
		||||
fn func2() -> Result<(), Box<Error>> {
 | 
			
		||||
    let filename = "foo.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
derive_str_cherr!(Func1ErrorFunc2);
 | 
			
		||||
derive_str_cherr!(Func1ErrorIO);
 | 
			
		||||
 | 
			
		||||
fn func1() -> Result<(), Box<Error>> {
 | 
			
		||||
    func2().map_err(mstrerr!(Func1ErrorFunc2, "func1 error calling func2"))?;
 | 
			
		||||
    let filename = "bar.txt";
 | 
			
		||||
    do_some_io().map_err(mstrerr!(Func1ErrorIO, "Error reading '{}'", filename))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<Error>> {
 | 
			
		||||
    if let Err(e) = func1() {
 | 
			
		||||
        if let Some(s) = e.downcast_ref::<ChainError<Func1ErrorIO>>() {
 | 
			
		||||
            eprintln!("Func1ErrorIO:\n{:?}", s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(s) = try_cherr_ref!(e, Func1ErrorFunc2) {
 | 
			
		||||
            eprintln!("Func1ErrorFunc2:\n{:?}", s);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										163
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										163
									
								
								src/lib.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
use std::error::Error;
 | 
			
		||||
use std::fmt::{Debug, Display, Formatter, Result};
 | 
			
		||||
use std::result::Result as StdResult;
 | 
			
		||||
 | 
			
		||||
pub struct ChainError<T> {
 | 
			
		||||
    #[cfg(feature = "fileline")]
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +9,8 @@ pub struct ChainError<T> {
 | 
			
		|||
    error_cause: Option<Box<dyn Error + 'static>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
 | 
			
		||||
 | 
			
		||||
impl<T: 'static + Display + Debug> ChainError<T> {
 | 
			
		||||
    #[cfg(feature = "fileline")]
 | 
			
		||||
    pub fn new(
 | 
			
		||||
| 
						 | 
				
			
			@ -39,11 +42,11 @@ impl<T: 'static + Display + Debug> ChainError<T> {
 | 
			
		|||
        Some(cause)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn find_cause<U: Error + 'static>(&self) -> Option<&(dyn Error + 'static)> {
 | 
			
		||||
    pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
 | 
			
		||||
        let mut cause = self as &(dyn Error + 'static);
 | 
			
		||||
        loop {
 | 
			
		||||
            if cause.is::<U>() {
 | 
			
		||||
                return Some(cause);
 | 
			
		||||
                return cause.downcast_ref::<U>();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            match cause.source() {
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +56,7 @@ impl<T: 'static + Display + Debug> ChainError<T> {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn find_kind<U: 'static + Display + Debug>(&self) -> Option<&ChainError<U>> {
 | 
			
		||||
    pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
 | 
			
		||||
        let mut cause = self as &(dyn Error + 'static);
 | 
			
		||||
        loop {
 | 
			
		||||
            if cause.is::<ChainError<U>>() {
 | 
			
		||||
| 
						 | 
				
			
			@ -229,6 +232,9 @@ macro_rules! mstrerr {
 | 
			
		|||
    ( $t:path, $v:expr $(, $more:expr)* ) => {
 | 
			
		||||
        |e| cherr!(e, $t (format!($v, $( $more , )* )))
 | 
			
		||||
    };
 | 
			
		||||
    ( $v:expr $(, $more:expr)* ) => {
 | 
			
		||||
        |e| cherr!(e, format!($v, $( $more , )* ))
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
| 
						 | 
				
			
			@ -245,138 +251,37 @@ macro_rules! derive_str_cherr {
 | 
			
		|||
                write!(f, "{}({})", stringify!($e), self.0)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        impl ::std::error::Error for $e {}
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! try_cherr_ref {
 | 
			
		||||
    ( $e:expr, $t:ident ) => {
 | 
			
		||||
        $e.downcast_ref::<ChainError<$t>>()
 | 
			
		||||
    };
 | 
			
		||||
    ( $e:expr, $t:path ) => {
 | 
			
		||||
        $e.downcast_ref::<ChainError<$t>>()
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! try_cherr_mut {
 | 
			
		||||
    ( $e:expr, $t:ident ) => {
 | 
			
		||||
        $e.downcast_mut::<ChainError<$t>>()
 | 
			
		||||
    };
 | 
			
		||||
    ( $e:expr, $t:path ) => {
 | 
			
		||||
        $e.downcast_mut::<ChainError<$t>>()
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub mod prelude {
 | 
			
		||||
    pub use super::{cherr, derive_str_cherr, mstrerr, ChainError, ChainErrorDown};
 | 
			
		||||
    pub use super::{
 | 
			
		||||
        cherr, derive_str_cherr, mstrerr, try_cherr_mut, try_cherr_ref, ChainError, ChainErrorDown,
 | 
			
		||||
        ChainResult,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use std::error::Error;
 | 
			
		||||
    use std::io::Error as IoError;
 | 
			
		||||
    use std::io::ErrorKind as IoErrorKind;
 | 
			
		||||
    use std::path::Path;
 | 
			
		||||
 | 
			
		||||
    use crate::prelude::*;
 | 
			
		||||
 | 
			
		||||
    #[derive(Clone, PartialEq, Debug)]
 | 
			
		||||
    enum ParseError {
 | 
			
		||||
        InvalidValue(u32),
 | 
			
		||||
        InvalidParameter(String),
 | 
			
		||||
        NoOpen,
 | 
			
		||||
        NoClose,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl ::std::fmt::Display for ParseError {
 | 
			
		||||
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
 | 
			
		||||
            match self {
 | 
			
		||||
                ParseError::InvalidValue(a) => write!(f, "InvalidValue: {}", a),
 | 
			
		||||
                ParseError::InvalidParameter(a) => write!(f, "InvalidParameter: '{}'", a),
 | 
			
		||||
                ParseError::NoOpen => write!(f, "No opening '{{' in config file"),
 | 
			
		||||
                ParseError::NoClose => write!(f, "No closing '}}' in config file"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn parse_config(c: String) -> Result<(), Box<Error>> {
 | 
			
		||||
        if !c.starts_with('{') {
 | 
			
		||||
            Err(cherr!(ParseError::NoOpen))?;
 | 
			
		||||
        }
 | 
			
		||||
        if !c.ends_with('}') {
 | 
			
		||||
            Err(cherr!(ParseError::NoClose))?;
 | 
			
		||||
        }
 | 
			
		||||
        let c = &c[1..(c.len() - 1)];
 | 
			
		||||
        let v = c
 | 
			
		||||
            .parse::<u32>()
 | 
			
		||||
            .map_err(|e| cherr!(e, ParseError::InvalidParameter(c.into())))?;
 | 
			
		||||
        if v > 100 {
 | 
			
		||||
            Err(cherr!(ParseError::InvalidValue(v)))?;
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    derive_str_cherr!(ConfigFileError);
 | 
			
		||||
    derive_str_cherr!(SeriousError);
 | 
			
		||||
    derive_str_cherr!(FileError);
 | 
			
		||||
    derive_str_cherr!(AppError);
 | 
			
		||||
 | 
			
		||||
    fn file_reader(_filename: &Path) -> Result<(), Box<Error>> {
 | 
			
		||||
        Err(IoError::from(IoErrorKind::NotFound))
 | 
			
		||||
            .map_err(mstrerr!(FileError, "File reader error"))?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_config(filename: &Path) -> Result<(), Box<Error>> {
 | 
			
		||||
        if filename.eq(Path::new("global.ini")) {
 | 
			
		||||
            // assume we got an IO error
 | 
			
		||||
            file_reader(filename).map_err(mstrerr!(
 | 
			
		||||
                ConfigFileError,
 | 
			
		||||
                "Error reading file {:?}",
 | 
			
		||||
                filename
 | 
			
		||||
            ))?;
 | 
			
		||||
        }
 | 
			
		||||
        // assume we read some buffer
 | 
			
		||||
        if filename.eq(Path::new("local.ini")) {
 | 
			
		||||
            let buf = String::from("{1000}");
 | 
			
		||||
            parse_config(buf)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if filename.eq(Path::new("user.ini")) {
 | 
			
		||||
            let buf = String::from("foo");
 | 
			
		||||
            parse_config(buf)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if filename.eq(Path::new("user2.ini")) {
 | 
			
		||||
            let buf = String::from("{foo");
 | 
			
		||||
            parse_config(buf)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if filename.eq(Path::new("user3.ini")) {
 | 
			
		||||
            let buf = String::from("{foo}");
 | 
			
		||||
            parse_config(buf)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if filename.eq(Path::new("custom.ini")) {
 | 
			
		||||
            let buf = String::from("{10}");
 | 
			
		||||
            parse_config(buf)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if filename.eq(Path::new("essential.ini")) {
 | 
			
		||||
            Err(cherr!(SeriousError("Something is really wrong".into())))?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_config_pre(p: &str) -> Result<(), Box<Error>> {
 | 
			
		||||
        read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_chain_error() {
 | 
			
		||||
        for p in &[
 | 
			
		||||
            "global.ini",
 | 
			
		||||
            "local.ini",
 | 
			
		||||
            "user.ini",
 | 
			
		||||
            "user2.ini",
 | 
			
		||||
            "user3.ini",
 | 
			
		||||
            "custom.ini",
 | 
			
		||||
            "essential.ini",
 | 
			
		||||
        ] {
 | 
			
		||||
            if let Err(e) = read_config_pre(p) {
 | 
			
		||||
                let app_err = e.downcast_chain_ref::<AppError>().unwrap();
 | 
			
		||||
 | 
			
		||||
                match p {
 | 
			
		||||
                    &"global.ini" => {
 | 
			
		||||
                        assert!(app_err.find_kind::<ConfigFileError>().is_some());
 | 
			
		||||
                        assert!(app_err.root_cause().unwrap().is::<IoError>());
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue