| Crates.io | anyhow-std |
| lib.rs | anyhow-std |
| version | 0.1.4 |
| created_at | 2023-04-08 15:29:10.497545+00 |
| updated_at | 2023-06-03 20:33:10.200048+00 |
| description | Wrap std APIs with anyhow error context. |
| homepage | https://github.com/nathan-at-least/anyhow-std |
| repository | https://github.com/nathan-at-least/anyhow-std.git |
| max_upload_size | |
| id | 833640 |
| size | 43,542 |
anyhow-stdThis crate wraps certain [std] functionality to produce [anyhow::Result]s providing better error messages w/ context.
Suppose we are processing a user-provided path and we expect it to have an extension that is valid UTF8:
use std::path::Path;
use anyhow_std::{PathAnyhow, OsStrAnyhow};
fn process_user_path(path: &Path) -> anyhow::Result<()> {
let extos = path.extension_anyhow()?;
let ext = extos.to_str_anyhow()?;
process_user_path_with_extension(path, ext)?;
Ok(())
}
fn process_user_path_with_extension(path: &Path, extension: &str) -> anyhow::Result<()> {
todo!("implement path processing of {path:?} for the extension {extension:?}")
}
/*
Now if the user provides a path without an extension, they'll get an
error message with more helpful context:
*/
let res = process_user_path(Path::new("/tmp/no-extension"));
assert!(res.is_err());
let error_message = format!("{:#}", res.err().unwrap());
assert_eq!(
error_message,
r#"while processing path "/tmp/no-extension": missing expected extension"#
);
/*
Unix systems can have non-UTF8 paths:
*/
#[cfg(target_family = "unix")]
fn demonstrate_non_utf8_extension() {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
let res = process_user_path(Path::new(OsStr::from_bytes(b"/tmp/non-unicode-extension.wacky-\xf3-extension")));
assert!(res.is_err());
let error_message = format!("{:#}", res.err().unwrap());
assert_eq!(
error_message,
r#"while processing os string "wacky-�-extension": not valid utf8"#,
);
}
#[cfg(target_family = "unix")]
demonstrate_non_utf8_extension();
A common pattern is used to extend [std] types:
<std type>Anyhow, for example: [OsStrAnyhow]impl OsStrAnyhow for OsStr { … }<method name>_anyhow. These methods always return [anyhow::Result] types, for example: [OsStrAnyhow::to_str_anyhow].…_anyhow methods may be provided to wrap functionality not found directly on the target type. For example Path::read_to_string does not exist, but would be a straightforward wrapper for [std::fs::read_to_string], so this crate provides [PathAnyhow::read_to_string_anyhow]By consistently appending _anyhow to wrapped methods, callers can
unambiguously choose when to use these methods versus the [std] methods.
…_anyhow MethodsThese methods convert Option<T> or Result<T, E> return types of
the [std] method into anyhow::Result<T>, where the [anyhow::Error]
has context added specific to the [std] type.
For [std] methods that return Option<T>, often a None return type
isn't necessarily an "error" per se, but the …_anyhow methods result
in an error in this case. So these methods should only be used when code
expects Some results, and if your code should handle None as a
"non-error", it can simply use the [std] method.
In some cases, it is necessary to use a "wrapper type" pattern rather than an extension trait, primarily to track extra data used in error contexts. For example the [crate::fs] wrapper types ReadDir, DirEntry, and Metadata each own a PathBuf in addition to the underlying [std::fs] type in order to provide paths in error contexts, in order to provide helpful error context for common directory and fs traversal uses.
Wrapper types override some underlying [std] type methods, rather
than using the …_anyhow naming convention. They also provide
a [std::ops::Deref] impl for the underlying [std] type, so all
non-overridden methods can be called naturally and overridden methods
can be called by explicitly using wrapper.deref().target_method(…).
Types using this wrapper-type pattern consistently provide [From] /
[Into] implementations where possible for the underlying [std] types plus
any error context data. For example, for [crate::fs::Metadata] provides
[From] / [Into] impls for (std::fs::Metadata, std::fs::PathBuf),
the latter providing error context. There is an exception to this
for Child because it mutates the underlying
[std::process::Child] upon construction.
Finally, the Output type is an exception to
this wrapper pattern because it provides no methods and exposes all
contents as pub fields.
This crate only wraps a small subset of [std] based on what the author needs in other projects. If you'd like to see more [std] APIs wrapped, patches are welcome. ;-)
The 0.1.x version series will add APIs as they are useful and may
change error context strings. The semantics of wrapped functions should
not vary much, but might.