1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
use crate::ErrorAnnotation;

/// Capture diagnostic information in a closure that extends a source error type into a wrapping
/// [`ErrorAnnotation`].
///
/// `annotate` captures a `label` and a diagnostic `info` construction closure, `mkinfo`, returning
/// a closure that creates an [`ErrorAnnotation`] given a source error of type `S`. This API design
/// makes it ergonomic to use as the parameter to `Result::map_err` to transform a source error
/// by extending it with diagnostic information.
///
/// `mkinfo` is a closure which allows deferring the construction of the diagnostic `info` until
/// the error case is encountered, similar to the design of `Option::ok_or_else`.
///
/// # Example
///
/// ```
/// use std::path::Path;
/// use std::fs::Metadata;
/// use error_annotation::{ErrorAnnotation, annotate};
///
/// type IoErrorWithPath<'a> = ErrorAnnotation<std::io::Error, std::path::Display<'a>>;
///
/// fn metadata(p: &Path) -> Result<Metadata, IoErrorWithPath> {
///   std::fs::metadata(p).map_err(annotate("path", || p.display()))
/// }
/// ```
pub fn annotate<S, F, I>(label: &'static str, mkinfo: F) -> impl FnOnce(S) -> ErrorAnnotation<S, I>
where
    F: FnOnce() -> I,
{
    move |source| ErrorAnnotation {
        source,
        label,
        info: mkinfo(),
    }
}