Crate quick_error [] [src]

A macro which makes errors easy to write

Minimum type is like this:

#[macro_use] extern crate quick_error;

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        Variant1 {}
    }
}

Both pub and non-public types may be declared, and all meta attributes (such as #[derive(Debug)]) are forwarded as is. The Debug must be implemented (but you may do that yourself if you like). The documentation comments /// something (as well as other meta attrbiutes) on variants are allowed.

You may add arbitrary parameters to any struct variant:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        /// IO Error
        Io(err: std::io::Error) {}
        /// Utf8 Error
        Utf8(err: std::str::Utf8Error) {}
    }
}

Note unlike in normal Enum decarations you declare names of fields (which are omitted from type). How they can be used is outlined below.

Now you might have noticed trailing braces {}. They are used to define implementations. By default:

  • Error::description() returns variant name as static string
  • Error::cause() returns None (even if type wraps some value)
  • Display outputs description()
  • No From implementations are defined

To define description simply add description(value) inside braces:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        Io(err: std::io::Error) {
            description(err.description())
        }
        Utf8(err: std::str::Utf8Error) {
            description("utf8 error")
        }
    }
}

Normal rules for borrowing apply. So most of the time description either returns constant string or forwards description from enclosed type.

To change cause method to return some error, add cause(value), for example:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        Io(err: std::io::Error) {
            cause(err)
            description(err.description())
        }
        Utf8(err: std::str::Utf8Error) {
            description("utf8 error")
        }
    }
}

Note you don't need to wrap value in Some, its implicit. In case you want None returned just omit the cause. You can't return None conditionally.

To change how each clause is Displayed add display(pattern,..args), for example:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        Io(err: std::io::Error) {
            display("I/O error: {}", err)
        }
        Utf8(err: std::str::Utf8Error) {
            display("Utf8 error, valid up to {}", err.valid_up_to())
        }
    }
}

If you need a reference to the error when Displaying, you can instead use display(x) -> (pattern, ..args), where x sets the name of the reference.

use std::error::Error; // put methods like `description()` of this trait into scope

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        Io(err: std::io::Error) {
            display(x) -> ("{}: {}", x.description(), err)
        }
        Utf8(err: std::str::Utf8Error) {
            display(self_) -> ("{}, valid up to {}", self_.description(), err.valid_up_to())
        }
    }
}

To convert to the type from any other, use one of the three forms of from clause.

For example, to convert simple wrapper use bare from():

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        Io(err: std::io::Error) {
            from()
        }
    }
}

This implements From<io::Error>.

To convert to singleton enumeration type (discarding the value), use the from(type) form:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        FormatError {
            from(std::fmt::Error)
        }
    }
}

And the most powerful form is from(var: type) -> (arguments...). It might be used to convert to type with multiple arguments or for arbitrary value conversions:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        FailedOperation(s: &'static str, errno: i32) {
            from(errno: i32) -> ("os error", errno)
            from(e: std::io::Error) -> ("io error", e.raw_os_error().unwrap())
        }
        /// Converts from both kinds of utf8 errors
        Utf8(err: std::str::Utf8Error) {
            from()
            from(err: std::string::FromUtf8Error) -> (err.utf8_error())
        }
    }
}

Since quick-error 1.1 we also have a context declaration, which is similar to (the longest form of) from, but allows adding some context to the error. We need a longer example to demonstrate this:

use quick_error::ResultExt;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        File(filename: PathBuf, err: io::Error) {
            context(path: &'a Path, err: io::Error)
                -> (path.to_path_buf(), err)
        }
    }
}

fn openfile(path: &Path) -> Result<(), Error> {
    try!(File::open(path).context(path));

    // If we didn't have context, the line above would be written as;
    //
    // try!(File::open(path)
    //     .map_err(|err| Error::File(path.to_path_buf(), err)));

    Ok(())
}

Each context(a: A, b: B) clause implements From<Context<A, B>> for Error. Which means multiple context clauses are a subject to the normal coherence rules. Unfortunately, we can't provide full support of generics for the context, but you may either use a lifetime 'a for references or AsRef<Type> (the latter means A: AsRef<Type>, and Type must be concrete). It's also occasionally useful to use a tuple as a type of the first argument.

You also need to use quick_error::ResultExt extension trait to get working .context() method.

More info on context in this article.

All forms of from, display, description, cause, and context clauses can be combined and put in arbitrary order. Only from and context can be used multiple times in single variant of enumeration. Docstrings are also okay. Empty braces can be omitted as of quick_error 0.1.3.

Macros

quick_error!

Main macro that does all the work

Structs

Context

Traits

ResultExt