as_result/
lib.rs

1use std::{
2    io,
3    process::{ExitStatus, Output},
4};
5
6#[cfg(unix)]
7use std::os::unix::process::ExitStatusExt as _;
8
9/// Converts the type into a `std::io::Result<()>` by reference
10pub trait AsResult<T, E> {
11    /// Converts the type into a `std::io::Result<()>` by reference
12    fn as_result(&self) -> Result<T, E>;
13}
14
15/// Converts the type into a `std::io::Result<()>`
16pub trait IntoResult<T, E> {
17    /// Converts the type into a `std::io::Result<()>`
18    fn into_result(self) -> Result<T, E>;
19}
20
21/// Maps a result into another result
22pub trait MapResult<T, E> {
23    /// Maps a result into another result
24    fn map_result(self) -> Result<T, E>;
25}
26
27impl AsResult<(), io::Error> for ExitStatus {
28    fn as_result(&self) -> io::Result<()> {
29        Err(if self.success() {
30            return Ok(());
31        } else if let Some(127) = self.code() {
32            io::Error::new(io::ErrorKind::NotFound, "command was not found")
33        } else {
34            #[cfg(unix)]
35            {
36                if let Some(signal) = self.signal() {
37                    return Err(io::Error::new(
38                        io::ErrorKind::Other,
39                        format!("terminated with signal {}", signal),
40                    ));
41                }
42            }
43
44            io::Error::new(io::ErrorKind::Other, format!("status is unknown: {}", self))
45        })
46    }
47}
48
49impl IntoResult<(), io::Error> for ExitStatus {
50    fn into_result(self) -> io::Result<()> {
51        self.as_result()
52    }
53}
54
55impl IntoResult<Output, io::Error> for Output {
56    fn into_result(self) -> io::Result<Output> {
57        self.status.as_result().map(|_| self)
58    }
59}
60
61impl MapResult<(), io::Error> for io::Result<ExitStatus> {
62    fn map_result(self) -> io::Result<()> {
63        self.and_then(IntoResult::into_result)
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use std::process::Command;
71
72    #[test]
73    fn command() {
74        Command::new("/bin/echo")
75            .arg("hello world")
76            .status()
77            .and_then(IntoResult::into_result)
78            .unwrap();
79
80        Command::new("/bin/echo")
81            .arg("hello world")
82            .status()
83            .unwrap()
84            .into_result()
85            .unwrap();
86
87        Command::new("/bin/echo")
88            .arg("hello world")
89            .status()
90            .map_result()
91            .unwrap()
92    }
93}