#replace #error-string #longer #anyhow #thiserror #error-context #error-chain

deprecated strerror

A string-based error type. No longer developed. Recommended replacement: Anyhow and Thiserror crates.

24 releases

0.6.3 Nov 9, 2020
0.6.2 Oct 16, 2019
0.5.1 Oct 9, 2019

#14 in #longer

27 downloads per month
Used in mango-client

MIT/Apache

21KB
278 lines

strerror

A string-based error type. No longer developed. Recommended replacement: Anyhow and Thiserror crates.

Documentation

See included rustdoc documentation or visit https://docs.rs/strerror.

Note that when building the documentation locally you currently need a nightly compiler to correctly render the RFC1946 intra-rustdoc links.

License

This project is licensed under the MIT license (LICENSE-MIT) or the Apache License, Version 2.0 (LICENSE-APACHE), at your option.


lib.rs:

A string-based error type. No longer developed. Recommended replacement: Anyhow and Thiserror crates.

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 you can use chain_error.

use std::io::Error as IoError;

let source = IoError::from_raw_os_error(5);
let err = source.chain_error("I/O error occurred");

Chaining chain_error method calls together creates an error chain.

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

gives output

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

Returning Results

While the chain_error 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 in the example above chair_err takes a closure, and not a String directly. This is so the construction of the String is not performed unless needed. You do not need to use closures however, since chair_err accepts Strings, and &strs as well.

Returning a new StrError in a Result can be done in the following way, taking advantage of From conversion from &str.


fn main() -> Result<(), StrError> {
    return Err("an error".into());
}

An alternative is the into_err method, which will call into and create the Err variant in one step.


fn main() -> Result<(), StrError> {
    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 or ok_or_else.

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

We take advantage again of From conversion from &str to return a StrError.

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 previously.

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_error("Failure reading disk")
        .chain_error("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

No runtime deps