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
//! Provides [`IoResultExt`], an extension trait for shortening common patterns with [`std::io::Result`].
#![deny(missing_docs)]
use std::io;
/// A collection of helper methods for [`std::io::Result`].
pub trait IoResultExt<T>: sealed::Sealed + Sized {
/// Map potentially [not found](`std::io::ErrorKind::NotFound`) entities to an [`Option`].
///
/// ```
/// # use std::fs::File;
/// # use io_result_ext::IoResultExt;
/// if let Some(config) = File::open("config.json").optional()? {
/// // do something...
/// }
/// # Ok::<(), std::io::Error>(())
/// ```
fn optional(self) -> io::Result<Option<T>>;
/// Mask [`ErrorKind::AlreadyExists`](`std::io::ErrorKind::AlreadyExists`) errors.
///
/// ```
/// # use std::fs;
/// # use io_result_ext::IoResultExt;
/// # fn test() -> std::io::Result<()> {
/// fs::create_dir("cache").can_exist()?;
/// // And then on a later run...
/// fs::create_dir("cache").can_exist()?;
/// # Ok(())
/// # }
/// ```
fn can_exist(self) -> Self
where
T: Default;
}
impl<T> IoResultExt<T> for io::Result<T> {
fn optional(self) -> io::Result<Option<T>> {
match self {
Ok(t) => Ok(Some(t)),
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(None),
Err(e) => Err(e),
}
}
fn can_exist(self) -> Self
where
T: Default,
{
match self {
Ok(t) => Ok(t),
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(T::default()),
Err(e) => Err(e),
}
}
}
mod sealed {
/// Prevent accidental implementations of other traits on external types.
///
/// For more information, see the [Rust API guidelines](https://rust-lang.github.io/api-guidelines/future-proofing.html).
pub trait Sealed {}
impl<T> Sealed for ::std::io::Result<T> {}
}