Crates.io | coded |
lib.rs | coded |
version | 0.1.0 |
source | src |
created_at | 2022-01-10 23:43:52.884979 |
updated_at | 2022-01-10 23:43:52.884979 |
description | concrete error type with an `ErrorKind` enum matching Google's "canonical error codes" |
homepage | |
repository | https://github.com/scottlamb/coded |
max_upload_size | |
id | 511955 |
size | 51,772 |
This is a concrete error type with an ErrorKind
enum matching
Google's "canonical error codes". You may know these from Google Cloud
errors,
absl::Status
, or
gRPC status codes.
The error code enum is exceptionally stable. The overall crate API is a work in progress. Ideas welcome!
I'll convert Moonfire NVR to this shortly.
use coded::{bail, err, Error, ErrorBuilder, ErrorKind, ResultExt};
/// Reads application config from its well-known paths.
fn read_config() -> Result<MyConfig, Error> {
for path in &PATHS {
match read_json(p) {
Ok(c) => return Ok(c),
Err(e) if e.kind() == ErrorKind::NotFound => { /* keep trying */ },
// The `bail!` macro is a convenient, flexible shorthand.
Err(e) => bail!(e, msg("can't read {}", p.display()))
}
}
// `bail!` lets us write `NotFound` without `use ErrorKind::*`.
bail!(NotFound, msg("no config file at any of {:?}", PATHS))
}
/// Reads a JSON object from the given path.
///
/// This returns an `ErrorBuilder` rather than an `Error`, avoiding a redundant
/// entry in the error chain when it's wrapped by the caller.
fn read_json<T: Deserialize>(p: &Path) -> Result<(), ErrorBuilder> {
// There's automatic conversion from std::io::Error to coded::ErrorBuilder which
// selects an appropriate ErrorKind.
let raw = std::fs::read(p)?;
// ResultExt::err_kind wraps any std::error::Error impl, using the supplied
// kind. It doesn't add a message.
serde_json::from_str(&raw).err_kind(ErrorKind::InvalidArgument)
}
fn main() {
if let Err(e) = inner_main() {
// `Error::chain` prints not only `e` itself but also the full chain of sources.
eprintln!("Fatal error:\n{}", e.chain());
std::process::exit(1);
}
}
fn inner_main() -> Result<(), Error> {
let config = read_config()?;
// ...
}
#[non_exhaustive]
because new codes could be
added, but this hasn't happened since 2015. This is great for RPC
or crate boundaries.Ok
has to be cheap. A Result<(), coded::Error>
is
one word, so returning Ok
is faster
than with larger error types.Cargo.toml
and environment variables).
In the future, perhaps
tracing_error::SpanTrace
and/or
arbitrary payloads.err!
and bail!
macros.anyhow
,
eyre
, or
snafu::Whatever
.coded
's API to reach 1.0. (Note: if there's demand, I could split
the absolutely-stable coded::{ErrorKind, ToErrorKind}
types into
their own crate. Then you could have a stable error type by wrapping
coded::Error
in your own crate's public Error
type.)Err
has to be cheap. coded::Error
isn't cheap: it
requires heap allocation, and currently stack traces can't be disabled for
particular libraries or call sites.?
without
having to make your own wrapper around those error types and/or
coded
. Due to Rust's orphan
rule,
coded::ToErrorKind
can only be implemented where the error is defined
or in coded
. This limits ergonomics. (Once specialization is stable,
?
could pass along other types using ErrorKind::Unknown
, but this
might be more of a footgun than a help. Likewise, we could fight the
orphan rule with something like
inventory
, but we probably
shouldn't.)Error Handling in a Correctness-Critical Rust Project
describes how many of these apply to the sled
database.
If you need your own error type but hate writing boilerplate, try the derive
macros from thiserror
or
snafu
).
Return coded::Error
. Use comments to document the error kinds your API
returns in certain situations. Feel free to add additional error kinds without a
semver break, as callers must match non-exhaustively.
absl::Status
supports. I'd like to use support baked into the std::error::Error
trait
for this (see RFC 2895) but
it doesn't exist yet. coded
might grow its own API for this in the
meantime.prost
,
protobuf
, and
quick-protobuf
). We could
support each via Cargo feature flags.Apache 2.0 or MIT, at your option.
Scott Lamb <slamb@slamb.org>