proc_result/
lib.rs

1//! A tiny cross-platforrm library containing exit status and code types.
2//!
3//! Unlike `std::process`, this crate does not require the standard library[^1], nor
4//! `libc`, and can create and interpret exit codes of non-current platforms. For
5//! example, on Windows, it can read and interpret exit codes that may have been
6//! recorded from a Linux process, or vice versa.
7//!
8//! [^1]: The `std` feature is enabled by default, but can be disabled.
9#![cfg_attr(not(feature = "std"), no_std)]
10
11use core::fmt::Display;
12
13use raw::RawExitCode;
14
15pub mod raw;
16pub mod unix;
17pub mod windows;
18
19// Import README.md so that doc tests run on it.
20#[allow(dead_code)]
21mod doc_tests {
22    #[doc = include_str!("../README.md")]
23    struct Readme;
24}
25
26/// An exit code or exit state returned by a program.
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28#[non_exhaustive]
29pub enum ProcResult {
30    /// An unclassified exit status on a Unix platform.
31    Unix(unix::WaitStatus),
32
33    /// An unclassified exit status on a Windows platform.
34    Windows(windows::ExitCode),
35}
36
37impl ProcResult {
38    /// Returns a result that is `Ok` if the exit code or status indicates a success.
39    ///
40    /// # Errors
41    ///
42    /// Returns `Self` if not [`ProcResult::is_success`].
43    pub fn ok(&self) -> Result<(), Self> {
44        if self.is_success() {
45            Ok(())
46        } else {
47            Err(*self)
48        }
49    }
50
51    /// Returns whether the process terminated successfully.
52    #[must_use]
53    pub fn is_success(&self) -> bool {
54        match self {
55            ProcResult::Unix(status) => status.exit_code().is_some_and(|code| code.is_success()),
56            ProcResult::Windows(code) => code.is_success(),
57        }
58    }
59
60    /// Returns whether the process did not terminate successfully.
61    #[must_use]
62    pub fn is_failure(&self) -> bool {
63        !self.is_success()
64    }
65}
66
67#[cfg(feature = "std")]
68impl Display for ProcResult {
69    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70        match self {
71            Self::Unix(status) => write!(f, "Unix exit status: {}", status.to_raw()),
72            Self::Windows(code) => write!(f, "Windows exit code: {}", code.to_raw()),
73        }
74    }
75}
76
77impl core::error::Error for ProcResult {}
78
79#[cfg(feature = "std")]
80impl From<std::process::ExitStatus> for ProcResult {
81    #[allow(unreachable_code)]
82    fn from(status: std::process::ExitStatus) -> Self {
83        #[cfg(unix)]
84        {
85            let err: unix::WaitStatus = status.into();
86            return Self::Unix(err);
87        }
88        #[cfg(windows)]
89        {
90            let err: windows::ExitCode = status.into();
91            return Self::Windows(err);
92        }
93        panic!("Cannot convert exit status to error on this platform");
94    }
95}