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 processuserpath(path: &Path) -> anyhow::Result<()> { let extos = path.extensionanyhow()?; let ext = extos.tostranyhow()?; processuserpathwith_extension(path, ext)?; Ok(()) }
fn processuserpathwithextension(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 = processuserpath(Path::new("/tmp/no-extension")); assert!(res.is_err());
let errormessage = format!("{:#}", res.err().unwrap()); asserteq!( error_message, r#"while processing path "/tmp/no-extension": missing expected extension"# );
/* Unix systems can have non-UTF8 paths: */
fn demonstratenonutf8_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"#,
);
}
demonstratenonutf8_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 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.
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.