[][src]Crate strerror

A string-based error type.

Introduction

This crate provides a string-based error type, StrError, that implements std::error::Error. It is for simple use cases where you wish to work with string errors and/or box existing errors of any type, adding context to them.

StrErrors behave in many ways like Strings, except they may also 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::*;

The examples below all assume use of the prelude.

Creating StrErrors

As with Strings, there are quite a few ways to create a StrError. Some have an analagous String equivalent, so are presented side-by-side with them.

// String                             // StrError
let str1 = "Error!".to_string();      let err1 = "Error!".into_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". To create a StrError with a source there are two equivalent ways, shown below. In each case the StrError takes ownership of the source which may or may not be another StrError.

use std::io::Error as IoError;

// Method 1: StrError::from_error
let source = IoError::from_raw_os_error(5);
let err1 = StrError::from_error(source, "I/O error occurred");
use std::io::Error as IoError;

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

Chaining chain method calls together creates an error chain.

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

gives output

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

Returning Results

While the chain method adds context to error types directly, we can do a similar thing with the Err variant values in Results, with the chain_err method.

use std::fs::File;

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

gives output

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

The Result is converted to the correct type by chain_err and context is applied to the boxed error. Note that chair_err takes a closure, and not a String directly. This is so the construction of the String is not performed unless needed.

If you are trying to return a Result using the return statement and the error in the return type of your function requires a From conversion from a StrError, you might try this.

use std::error::Error as StdError;

fn main() -> Result<(), Box<dyn StdError>> {
    return Err("an error".into_error().into());
}

However, the into_err method is easier since it will call into and create the Err variant in one step.

use std::error::Error as StdError;

fn main() -> Result<(), Box<dyn StdError>> {
    return "an error".into_error().into_err();
}

or even simpler

use std::error::Error as StdError;

fn main() -> Result<(), Box<dyn StdError>> {
    return "an error".into_err();
}

Converting Options

Sometimes None represents an application error and it is desirable to convert an Option<T> into a Result<T, StrError>. There is no special method needed in this case. You can use ok_or_else with a StrError.

use std::env;

fn main() -> Result<(), StrError> {
    let _ = env::var_os("MISSING_VAR")                         // an Option
        .ok_or_else(|| "MISSING_VAR not found".into_error())?; // exits
    Ok(())
}

gives output

Error: MISSING_VAR not found

If your containing function returns a Result<T, StrError>, like in the case above, it is sufficient and simpler to pass a &str to ok_or or a closure returning a String to ok_or_else. This produces a Result<T, &str> or Result<T, String>, but when used with the ? operator it is converted to a Result<T, StrError>. This works because StrError implements From<&str> and From<String>.

use std::env;

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

gives output

Error: MISSING_VAR not found

From conversions to StrError

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

use std::fs::File;

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

gives output

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

From conversions are also implemented for &str and String, as mentioned in the previous section.

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<T, E> into a Result<T, StrError>. Of course you may choose to use a Box<dyn std::error::Error> instead of a StrError in the the return type of your function, in which case ? 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".into_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, StringIntoErrExt and StringIntoErrorExt

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 variant value within a Result to a StrError.

StringIntoErrExt

Trait providing into_err for converting a String or &str to an Err variant Result.

StringIntoErrorExt

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