io_result_ext/lib.rs
1//! Provides [`IoResultExt`], an extension trait for shortening common patterns with [`std::io::Result`].
2#![deny(missing_docs)]
3
4use std::io;
5
6/// A collection of helper methods for [`std::io::Result`].
7pub trait IoResultExt<T>: sealed::Sealed + Sized {
8 /// Map potentially [not found](`std::io::ErrorKind::NotFound`) entities to an [`Option`].
9 ///
10 /// ```
11 /// # use std::fs::File;
12 /// # use io_result_ext::IoResultExt;
13 /// if let Some(config) = File::open("config.json").optional()? {
14 /// // do something...
15 /// }
16 /// # Ok::<(), std::io::Error>(())
17 /// ```
18 fn optional(self) -> io::Result<Option<T>>;
19
20 /// Mask [`ErrorKind::AlreadyExists`](`std::io::ErrorKind::AlreadyExists`) errors.
21 ///
22 /// ```
23 /// # use std::fs;
24 /// # use io_result_ext::IoResultExt;
25 /// # fn test() -> std::io::Result<()> {
26 /// fs::create_dir("cache").can_exist()?;
27 /// // And then on a later run...
28 /// fs::create_dir("cache").can_exist()?;
29 /// # Ok(())
30 /// # }
31 /// ```
32 fn can_exist(self) -> Self
33 where
34 T: Default;
35}
36
37impl<T> IoResultExt<T> for io::Result<T> {
38 fn optional(self) -> io::Result<Option<T>> {
39 match self {
40 Ok(t) => Ok(Some(t)),
41 Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(None),
42 Err(e) => Err(e),
43 }
44 }
45
46 fn can_exist(self) -> Self
47 where
48 T: Default,
49 {
50 match self {
51 Ok(t) => Ok(t),
52 Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(T::default()),
53 Err(e) => Err(e),
54 }
55 }
56}
57
58mod sealed {
59 /// Prevent accidental implementations of other traits on external types.
60 ///
61 /// For more information, see the [Rust API guidelines](https://rust-lang.github.io/api-guidelines/future-proofing.html).
62 pub trait Sealed {}
63
64 impl<T> Sealed for ::std::io::Result<T> {}
65}