anyhow_auto_context/
lib.rs1#![doc = include_str!("../README.md")]
2
3#[macro_export]
27macro_rules! auto_context {
28 (@location $result:expr_2021) => {{
29 const fn f() {}
30 fn type_name<T>(_: T) -> &'static str {
31 ::std::any::type_name::<T>()
32 }
33 let scope = type_name(f)
34 .strip_suffix("::f")
35 .unwrap_or_default()
36 .trim_end_matches("::{{closure}}");
37 format!(
38 "{} in {} at {}:{}:{}",
39 stringify!($result),
40 scope,
41 file!(),
42 line!(),
43 column!(),
44 )
45 }};
46 ($result:expr_2021 $(,)?) => {
47 anyhow::Context::with_context($result, || $crate::auto_context!(@location $result))
48 };
49 ($result:expr_2021, $($context:tt)+) => {
50 anyhow::Context::with_context($result, || {
51 let location = $crate::auto_context!(@location $result);
52 format!("{location} with {}", format!($($context)+))
53 })
54 };
55}
56
57#[cfg(test)]
58mod tests {
59 fn ensure_42(n: i32) -> anyhow::Result<()> {
60 anyhow::ensure!(n == 42, "Expected 42");
61 Ok(())
62 }
63
64 #[test]
65 fn ok() {
66 assert!(auto_context!(ensure_42(42)).is_ok());
67 }
68
69 #[test]
70 fn err() {
71 let err_str = auto_context!(ensure_42(0)).unwrap_err().to_string();
72 assert!(err_str.starts_with("ensure_42(0) in"), "{err_str}");
73 }
74
75 #[test]
76 fn some() {
77 assert_eq!(auto_context!(Some(42)).unwrap(), 42);
78 }
79
80 #[test]
81 fn none() {
82 let expected_some: Option<i32> = None;
83
84 let err_str = auto_context!(expected_some).unwrap_err().to_string();
85 assert!(err_str.starts_with("expected_some in"), "{err_str}");
86 }
87
88 #[test]
89 fn err_with_custom_context() {
90 let user = "Alice";
91
92 let err_str = auto_context!(ensure_42(0), "user {user}")
93 .unwrap_err()
94 .to_string();
95 assert!(err_str.starts_with("ensure_42(0) in"), "{err_str}");
96 assert!(err_str.ends_with("with user Alice"), "{err_str}");
97 }
98
99 #[test]
100 fn none_with_custom_context() {
101 let user = "Alice";
102 let expected_some: Option<i32> = None;
103
104 let err_str = auto_context!(expected_some, "user {user}")
105 .unwrap_err()
106 .to_string();
107 assert!(err_str.starts_with("expected_some in"), "{err_str}");
108 assert!(err_str.ends_with("with user Alice"), "{err_str}");
109 }
110}