Crate throw[][src]

Throw!

Throw is a new experimental rust error handling library, meant to assist and build on existing error handling systems.

Throw exports two structs, throw::ErrorPoint and throw::Error. throw::Error stores a single original_error variable which it is created from, and then a list of ErrorPoints which starts out with the original point of creation with throw!(), and is added to every time you propagate the error upwards with up!().

Throw does not replace existing error handling systems. The throw::Error type has a type parameter E which represents an internal error type stored. throw::Error just wraps your error type and stores ErrorPoints alongside it.

Throw helps you better keep track of your errors. Instead of seeing a generic "No such file or directory" message, you get a stack trace of functions which propagated the error as well.

Instead of:

IO Error: failed to lookup address information: Name or service not known

Get:

Error: IO Error: failed to lookup address information: Name or service not known
    at 79:17 in zaldinar::startup (src/startup.rs)
    at 104:4 in zaldinar::startup (src/startup.rs)
    at 28:17 in zaldinar_irclib (/home/daboross/Projects/Rust/zaldinar/zaldinar-irclib/src/lib.rs)

Using throw!

The main way you use throw is through two macros, throw!() and up!(). throw!() is used when you have a regular (non-throw) result coming from some library function that you want to propagate upwards in case of an error. up!() is used when you have an error which was created using throw!() in a sub-function which you want to add an error point to and propagate upwards.

Here's an example of throw in action:

#[macro_use]
extern crate throw;

use std::io::prelude::*;
use std::io;
use std::fs::File;

fn read_log() -> Result<String, throw::Error<io::Error>> {
    let mut file = throw!(File::open("some_file.log"));
    let mut buf = String::new();
    throw!(file.read_to_string(&mut buf));
    Ok((buf))
}

fn do_things() -> Result<(), throw::Error<io::Error>> {
    let log_contents = up!(read_log());
    println!("Log contents: {}", log_contents);

    Ok(())
}

fn main() {
    let result = do_things();
    if let Err(e) = result {
        panic!("{}", e);
    }
}

This simple program behaves exactly as if Result<_, io::Error> directly when it functions correctly. When the program encounters is when throw really shines. This will result in an error message:

Error: No such file or directory (os error 2)
   at 16:23 in main (src/main.rs)
   at 9:19 in main (src/main.rs)

These stack traces are stored inside throw::Error, and are recorded automatically when throw!() or up!() returns an Err value.

In each at line, the 16:23 represents line_num:column_num, the main represents the module path (for example my_program::sub_module), and src/main.rs represents the path of the file in which throw!() was used in.


Throwing directly from a function is also supported, using throw_new!():

fn possibly_fails() -> Result<(), throw::Error<&'static str>> {
    if true {
        // throw_new!() will always return directly
        throw_new!("oops");
    }

    Ok(())
}

fn main() {
    possibly_fails().unwrap()
}
called `Result::unwrap()` on an `Err` value: Error: "oops"
   at 6:8 in main (src/main.rs)

throw_new!() differs from throw!() in that it takes a parameter directly to pass to a throw::Error, rather than a Result<> to match on. throw_new!() will always return directly from the function.


no_std

Throw offers support for no_std, with the caveat that a dependency on alloc is still required for Vec support. (throw uses a Vec to store error points within an error.)

To use this feature, depend on throw with default-features = false:

[dependencies]
throw = { version = "0.1", default-features = "false" }

Key/value pairs

Throw supports adding key/value pairs to errors to provide additional context information. In order to use this, simply add any number of "key_name" => value, arguments to any of the macros throw exports. value can be any integer type, float type, an &'static str, or an owned string.

fn possibly_fails(process_this: &str) -> Result<(), throw::Error<&'static str>> {
    if true {
        throw_new!("oops", "processing" => process_this.to_owned());
    }

    Ok(())
}

fn main() {
    possibly_fails("hello").unwrap()
}

Results in:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error: "oops"
    processing: hello
    at 6:9 in rust_out (src/lib.rs)', libcore/result.rs:945:5

Serde support

To have serde::{Serialize, Deserialize} implemented on Throw types, depend on throw with features = ["serde-1-std"] or features = ["serde-1"] for no-std environments.

Macros

throw
throw_new
up

Structs

Error

Represents an error. Stores an original error of type E, and any number of ErrorPoints at which the error was propagated.

ErrorPoint

Represents a location at which an error was thrown via throw!()

KvPair

represent a key-value pair

Enums

ThrowContextValues

Types allowed to be value in the context vector

Type Definitions

Result

Result alias for a result containing a throw::Error.