5 个版本
0.1.4 | 2023 年 6 月 3 日 |
---|---|
0.1.3 | 2023 年 4 月 27 日 |
0.1.2 | 2023 年 4 月 15 日 |
0.1.1 | 2023 年 4 月 8 日 |
0.1.0 | 2023 年 4 月 8 日 |
#8 在 #error-context
113 每月下载量
用于 4 个包 (2 直接)
44KB
1K SLoC
anyhow-std
此包封装了某些 [std] 功能以生成提供更好错误上下文的 anyhow::Result。
示例:期望一个有效的 UTF8 路径扩展
假设我们正在处理用户提供的路径,并 期望 它具有一个有效的 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();
扩展特质
使用一种常见的模式来扩展 [std] 类型
- 提供了一个名为
<std type>Anyhow
的扩展特质,例如:[OsStrAnyhow] - 提供了针对目标类型的 impl,例如
impl OsStrAnyhow for OsStr { … }
- 为目标类型的某些方法提供了扩展特质方法,方法名为
<method name>_anyhow
。这些方法始终返回 anyhow::Result 类型,例如:OsStrAnyhow::to_str_anyhow
。 - 此外,还提供了一些
…_anyhow
方法来封装在目标类型上找不到的功能。例如,Path::read_to_string
不存在,但可以作为一个简单的包装器,因此这个包提供了PathAnyhow::read_to_string_anyhow
通过始终将 _anyhow
添加到包装方法中,调用者可以明确选择何时使用这些方法与 [std] 方法。
…_anyhow
方法
这些方法将[std]方法返回的类型Option<T>
或Result<T, E>
转换为anyhow::Result<T>
,其中anyhow::Error
添加了针对[std]类型的特定上下文。
对于返回Option<T>
的[std]方法,通常返回类型为None
并不一定是“错误”,但是在这种情况下,…_anyhow
方法会导致错误。因此,这些方法只能在代码期望Some
结果时使用,如果您的代码应该将None
视为“非错误”,则可以简单地使用[std]方法。
包装类型
在某些情况下,需要使用“包装类型”模式而不是扩展特质,主要是为了跟踪错误上下文中使用的额外数据。例如,crate::fs包装类型ReadDir、DirEntry和Metadata各自除了拥有底层std::fs类型外,还拥有PathBuf,以便在错误上下文中提供路径,以便为常见的目录和文件系统遍历使用提供有用的错误上下文。
包装类型覆盖了一些底层[std]类型的方法,而不是使用…_anyhow
命名约定。它们还提供了一个std::ops::Deref实现,以便对底层[std]类型进行操作,因此可以自然地调用所有未覆盖的方法,并通过显式使用wrapper.deref().target_method(…)
来调用覆盖的方法。
使用这种包装类型模式的类型始终在可能的情况下为底层[std]类型以及任何错误上下文数据提供[From] / [Into]实现。例如,对于crate::fs::Metadata,提供了[From] / [Into]实现,为(std::fs::Metadata, std::fs::PathBuf)
,后者提供错误上下文。对于Child有一个例外,因为它在构造时修改了底层的std::process::Child。
最后,Output类型是这种包装模式的一个例外,因为它不提供任何方法,并将所有内容公开为pub
字段。
API 覆盖范围
这个crate只包装了作者在其他项目中需要的基于[std]的小子集。如果您想看到更多[std] API被包装,欢迎提交补丁。;-)
《0.1.x
》版本系列将根据有用性添加API,并可能更改错误上下文字符串。封装函数的语义不应有很大变化,但可能会。
依赖项
~0.4–0.9MB
~20K SLoC