[][src]Crate strerror

A string-based error type.

Introduction

This crate provides a string-based error type, StrError, that implements std::error::Error. StrErrors behave much like Strings, except they may contain another error boxed inside them, known as the "source" or "cause". Since the source can have a source itself, sources form chains of errors, each error adding context to the preceeding one.

When a StrError is returned from main, its Debug implementation causes the output of a CLI application to look like this

Error: ...
Caused by: ...
Caused by: ...
...

Each "Caused by:" line corresponds to a boxed error in the chain of sources.

The prelude

This crate has a prelude to bring in all the things you need at once.

use strerror::prelude::*;

Because some of the crate's functionality is contained in extension traits, this is quite useful. The examples below all assume the prelude is used.

Creating StrErrors

As with Strings, there are quite a few ways to create a StrError. Some have a String equivalent so we present these alongside each other.

// String                             // StrError
let str1 = "Error!".to_string();      let err1 = "Error!".to_error();
let str2 = String::from("Error!");    let err2 = StrError::from("Error!");
let str3: String = "Error!".into();   let err3: StrError = "Error!".into();
let str4 = format!("Error! #{}", 1);  let err4 = eformat!("Error! #{}", 1);

The above lines all create StrErrors without a "source" or "cause". Next we show two equivalent ways to create a StrError containing a source. The StrError takes ownership of the source which may or may not be another StrError.

use std::io::Error as IoError;

let source1 = IoError::from_raw_os_error(5);
let err1 = StrError::from_error(source1, "I/O error occurred");

let source2 = IoError::from_raw_os_error(5);
let err2 = source2.chain("I/O error occurred");

The advantage of the second way using the chain method comes from the fact that, in chaining methods together, an error chain itself can be created.

fn main() -> Result<(), StrError> {
    let err = "Base error".to_error()
        .chain("Higher level error")
        .chain("Application error");
    Err(err)
}

gives output

Error: Application error
Caused by: Higher level error
Caused by: Base error

Working with Results and Options

While the chain method adds context to error types directly, we can do a similar thing with the Err value within a Result with the chain_err method.

use std::fs::File;

fn main() -> Result<(), StrError> {
    let file = "missing-file";
    let _ = File::open(file)                                  // returns a Result
        .chain_err(format!("Failed to open file {}", file))?; // main exits here
    Ok(())
}

gives output

Error: Failed to open file missing-file
Caused by: No such file or directory (os error 2)

With Options no special method is needed to transform one into a Result with a StrError. We can just use ok_or and ok_or_else with a newly created one.

However, it is often sufficient to pass just a &str or String. This gives a Result containing a &str or String for its Err value, but when used with the ? operator it gets converted to a StrError. This works because StrError implements From<&str> and From<String>.

use std::env;

fn main() -> Result<(), StrError> {
    let _ = env::var_os("MISSING_VAR")                         // returns an Option
        .ok_or("Environment variable MISSING_VAR not found")?; // main exits here
    Ok(())
}

gives

Error: Environment variable MISSING_VAR not found

From conversions for other error types

From conversions are implemented for most of the standard library error types, so you can return a Result containing one directly from a function that returns a Result containing a StrError, using the ? operator.

use std::fs::File;

fn main() -> Result<(), StrError> {
    let file = "missing-file";
    let _ = File::open(file)?; // main exits here
    Ok(())
}

gives output

Error: std::io::Error
Caused by: No such file or directory (os error 2)

As mentioned when discussing Options, From conversions are also implemented for &str and String.

However, for other error types, if you wish to use the ? operator, you will first need to call the chain_err method to convert the Result into one containing a StrError. Of course you may choose to return a Result containing a Box<dyn std::error::Error> from your function instead, for which ? will work for all error types.

Deref

StrErrors deref to a String, so you can use many of the usual String methods.

fn main() -> Result<(), StrError> {
    let mut err = "This is".to_error();
    *err += " an error";
    err.push_str(" message");
    Err(err)
}

gives output

Error: This is an error message

Iterating through the source chain

A reference to a StrError can be iterated over to examine its chain of boxed sources.

use std::io::Error as IoError;

fn main() -> Result<(), StrError> {
    let err = IoError::from_raw_os_error(5)
        .chain("Failure reading disk")
        .chain("Application error");
    for e in &err {
        println!(
            "Error: {:31} Is StrError?: {}",
            e,
            e.downcast_ref::<StrError>().is_some()
        );
    }
    Ok(())
}

gives output

Error: Application error               Is StrError?: true
Error: Failure reading disk            Is StrError?: true
Error: Input/output error (os error 5) Is StrError?: false

Modules

prelude

Reexports of eformat, ErrorChainExt, ResultChainErrExt, StrError and StringToErrorExt.

Macros

eformat

A macro for creating a StrError using interpolation of runtime expressions (like format!).

Structs

Iter

An iterator producing a reference to a StrError (as a trait object), followed by its chain of sources.

StrError

A string-based error type implementing std::error::Error.

Traits

ErrorChainExt

Trait providing chain for converting an error of any type to a StrError.

ResultChainErrExt

Trait providing chain_err for mapping the Err value within a Result to a StrError.

StringToErrorExt

Trait providing to_error for converting a String or &str to a StrError.