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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Extensions for the [`Result`] type.
use std::io;
use crate::private::Sealed;
/// Extensions for the [`Result`] type.
#[allow(private_bounds)]
pub trait ResultEx<T, E>: Sealed {
/// Ignores the subset of the error for which the `check` returns true,
/// returning `None` instead.
///
/// # Examples
/// ```no_run
/// # use std::fs;
/// # use std::io::ErrorKind;
/// use tytanic_utils::result::ResultEx;
/// // if foo doesn't exist we get None
/// // if another error is returned it is propagated
/// assert_eq!(
/// fs::read_to_string("foo.txt").ignore(
/// |e| e.kind() == ErrorKind::NotFound,
/// )?,
/// Some(String::from("foo")),
/// );
/// assert_eq!(
/// fs::read_to_string("not-found.txt").ignore(
/// |e| e.kind() == ErrorKind::NotFound,
/// )?,
/// None,
/// );
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
fn ignore<F>(self, check: F) -> Result<Option<T>, E>
where
F: FnOnce(&E) -> bool;
/// Ignores the subset of the error for which the `check` returns true,
/// returning `Default::default` instead.
///
/// # Examples
/// ```no_run
/// # use std::fs;
/// # use std::io::ErrorKind;
/// use tytanic_utils::result::ResultEx;
/// // if foo doesn't exist we get ""
/// // if another error is returned it is propagated
/// assert_eq!(
/// fs::read_to_string("foo.txt").ignore_default(
/// |e| e.kind() == ErrorKind::NotFound,
/// )?,
/// String::from("foo"),
/// );
/// assert_eq!(
/// fs::read_to_string("not-found.txt").ignore_default(
/// |e| e.kind() == ErrorKind::NotFound,
/// )?,
/// String::new(),
/// );
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
fn ignore_default<F>(self, check: F) -> Result<T, E>
where
T: Default,
F: FnOnce(&E) -> bool;
/// Ignores the subset of the error for which the `check` returns true,
/// returning the result of `value` instead.
///
/// # Examples
/// ```no_run
/// # use std::fs;
/// # use std::io::ErrorKind;
/// use tytanic_utils::result::ResultEx;
/// // if foo doesn't exist we get "foo"
/// // if another error is returned it is propagated
/// assert_eq!(
/// fs::read_to_string("foo.txt").ignore_with(
/// |e| e.kind() == ErrorKind::NotFound,
/// |_| String::from("foo"),
/// )?,
/// String::from("foo"),
/// );
/// assert_eq!(
/// fs::read_to_string("not-found.txt").ignore_with(
/// |e| e.kind() == ErrorKind::NotFound,
/// |_| String::from("foo"),
/// )?,
/// String::from("bar"),
/// );
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
fn ignore_with<F, G>(self, check: F, value: G) -> Result<T, E>
where
F: FnOnce(&E) -> bool,
G: FnOnce(&E) -> T;
}
impl<T, E> ResultEx<T, E> for Result<T, E> {
fn ignore<F>(self, check: F) -> Result<Option<T>, E>
where
F: FnOnce(&E) -> bool,
{
self.map(Some).ignore_with(check, |_| None)
}
fn ignore_default<F>(self, check: F) -> Result<T, E>
where
T: Default,
F: FnOnce(&E) -> bool,
{
self.ignore_with(check, |_| T::default())
}
fn ignore_with<F, G>(self, check: F, value: G) -> Result<T, E>
where
F: FnOnce(&E) -> bool,
G: FnOnce(&E) -> T,
{
match self {
Err(err) if check(&err) => Ok(value(&err)),
x => x,
}
}
}
/// A check for [`ResultEx`] methods which ignores [`io::ErrorKind::NotFound`].
///
/// # Examples
/// ```no_run
/// # use std::fs;
/// # use std::io::ErrorKind;
/// use tytanic_utils::result::ResultEx;
/// use tytanic_utils::result::io_not_found;
/// assert_eq!(
/// fs::read_to_string("found.txt").ignore_default(io_not_found)?,
/// String::from("foo"),
/// );
/// assert_eq!(
/// fs::read_to_string("not-found.txt").ignore_default(io_not_found)?,
/// String::from(""),
/// );
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
pub fn io_not_found(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::NotFound
}