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
37
38
39
40
// Copyright © 2019-2020 The Radicle Foundation <hello@radicle.foundation>
//
// This file is part of radicle-link, distributed under the GPLv3 with Radicle
// Linking Exception. For full terms see the included LICENSE file.

pub trait ResultExt<T, E> {
    /// Calls `f` if the result is [`Err`], **and** the predicate `pred` on the
    /// error value returns true. Otherwise returns the [`Ok`] value of
    /// `self`. Note that `f` may change the error type, so as long as the
    /// target type can be converted from the original one.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io;
    /// use radicle_std_ext::result::ResultExt as _;
    ///
    /// let res = Err(io::Error::new(io::ErrorKind::Other, "crashbug"))
    ///     .or_matches::<io::Error, _, _>(|e| matches!(e.kind(), io::ErrorKind::Other), || Ok(()))
    ///     .unwrap();
    ///
    /// assert_eq!((), res)
    /// ```
    fn or_matches<E2, P, F>(self, pred: P, f: F) -> Result<T, E2>
    where
        E2: From<E>,
        P: FnOnce(&E) -> bool,
        F: FnOnce() -> Result<T, E2>;
}

impl<T, E> ResultExt<T, E> for Result<T, E> {
    fn or_matches<E2, P, F>(self, pred: P, f: F) -> Result<T, E2>
    where
        E2: From<E>,
        P: FnOnce(&E) -> bool,
        F: FnOnce() -> Result<T, E2>,
    {
        self.or_else(|e| if pred(&e) { f() } else { Err(e.into()) })
    }
}