Skip to content

Commit 60a4d96

Browse files
committed
unix: impl ExitStatusExt for ExitStatusError
It is unergnomic to have to say things like bad.into_status().signal() Implementing `ExitStatusExt` for `ExitStatusError` fixes this. Unfortunately it does mean making a previously-infallible method capable of panicing, although of course the existing impl remains infallible. The alternative would be a whole new `ExitStatusErrorExt` trait. `<ExitStatus as ExitStatusExt>::into_raw()` is not particularly ergonomic to call because of the often-required type annotation. See for example the code in the test case in library/std/src/sys/unix/process/process_unix/tests.rs Perhaps we should provide equivalent free functions for `ExitStatus` and `ExitStatusExt` in std::os::unix::process and maybe deprecate this trait method. But I think that is for the future. Signed-off-by: Ian Jackson <[email protected]>
1 parent e893089 commit 60a4d96

File tree

2 files changed

+76
-10
lines changed

2 files changed

+76
-10
lines changed

library/std/src/os/unix/process.rs

+70-7
Original file line numberDiff line numberDiff line change
@@ -195,28 +195,62 @@ impl CommandExt for process::Command {
195195
}
196196
}
197197

198-
/// Unix-specific extensions to [`process::ExitStatus`].
198+
/// Unix-specific extensions to [`process::ExitStatus`] and
199+
/// [`ExitStatusError`](process::ExitStatusError).
199200
///
200-
/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as passed to the
201-
/// `exit` system call or returned by [`ExitStatus::code()`](crate::process::ExitStatus::code).
202-
/// It represents **any wait status**, as returned by one of the `wait` family of system calls.
201+
/// On Unix, `ExitStatus` and `ExitStatusError` **do not necessarily represent an exit status**, as
202+
/// passed to the `exit` system call or returned by
203+
/// [`ExitStatus::code()`](crate::process::ExitStatus::code). They represents **any wait status**
204+
/// (or any nonzero wait status, respectively), as returned by one of the `wait` family of system
205+
/// calls.
203206
///
204-
/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but
205-
/// can also represent other kinds of process event.
207+
/// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
208+
/// represent other kinds of process event.
206209
///
207210
/// This trait is sealed: it cannot be implemented outside the standard library.
208211
/// This is so that future additional methods are not breaking changes.
209212
#[stable(feature = "rust1", since = "1.0.0")]
210213
pub trait ExitStatusExt: Sealed {
211-
/// Creates a new `ExitStatus` from the raw underlying integer status value from `wait`
214+
/// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
215+
/// value from `wait`
212216
///
213217
/// The value should be a **wait status, not an exit status**.
218+
///
219+
/// # Panics
220+
///
221+
/// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
222+
///
223+
/// Making an `ExitStatus` always succeds and never panics.
214224
#[stable(feature = "exit_status_from", since = "1.12.0")]
215225
fn from_raw(raw: i32) -> Self;
216226

217227
/// If the process was terminated by a signal, returns that signal.
218228
///
219229
/// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
230+
///
231+
/// # Examples
232+
/// ```
233+
/// #![feature(exit_status_error)]
234+
/// use std::process::{Command, ExitStatusError};
235+
/// use std::os::unix::process::ExitStatusExt;
236+
///
237+
/// fn run(script: &str) -> Result<(), ExitStatusError> {
238+
/// Command::new("sh").args(&["-ec",script])
239+
/// .status().expect("failed to fork/exec sh")
240+
/// .exit_ok()
241+
/// .or_else(|bad| {
242+
/// if bad.signal() == Some(13) /*PIPE*/ {
243+
/// Ok(())
244+
/// } else {
245+
/// Err(bad)
246+
/// }
247+
/// })
248+
/// }
249+
///
250+
/// run("exit").unwrap();
251+
/// run("kill -PIPE $$").unwrap();
252+
/// run("exit 42").unwrap_err();
253+
/// ```
220254
#[stable(feature = "rust1", since = "1.0.0")]
221255
fn signal(&self) -> Option<i32>;
222256

@@ -272,6 +306,35 @@ impl ExitStatusExt for process::ExitStatus {
272306
}
273307
}
274308

309+
#[unstable(feature = "exit_status_error", issue = "84908")]
310+
impl ExitStatusExt for process::ExitStatusError {
311+
fn from_raw(raw: i32) -> Self {
312+
process::ExitStatus::from_raw(raw)
313+
.exit_ok()
314+
.expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
315+
}
316+
317+
fn signal(&self) -> Option<i32> {
318+
self.into_status().signal()
319+
}
320+
321+
fn core_dumped(&self) -> bool {
322+
self.into_status().core_dumped()
323+
}
324+
325+
fn stopped_signal(&self) -> Option<i32> {
326+
self.into_status().stopped_signal()
327+
}
328+
329+
fn continued(&self) -> bool {
330+
self.into_status().continued()
331+
}
332+
333+
fn into_raw(self) -> i32 {
334+
self.into_status().into_raw()
335+
}
336+
}
337+
275338
#[stable(feature = "process_extensions", since = "1.2.0")]
276339
impl FromRawFd for process::Stdio {
277340
#[inline]

library/std/src/process.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,10 @@ impl fmt::Display for ExitStatus {
15001500
}
15011501
}
15021502

1503+
/// Allows extension traits within `std`.
1504+
#[unstable(feature = "sealed", issue = "none")]
1505+
impl crate::sealed::Sealed for ExitStatusError {}
1506+
15031507
/// Describes the result of a process after it has failed
15041508
///
15051509
/// Produced by the [`.exit_ok`](ExitStatus::exit_ok) method on [`ExitStatus`].
@@ -1536,9 +1540,8 @@ impl ExitStatusError {
15361540
/// runtime system (often, for example, 255, 254, 127 or 126).
15371541
///
15381542
/// On Unix, this will return `None` if the process was terminated by a signal. If you want to
1539-
/// handle such situations specially, consider using
1540-
/// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt) (possibly after getting the
1541-
/// general `ExitStatus` by using [`status()`](ExitStatusError::status).
1543+
/// handle such situations specially, consider using methods from
1544+
/// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt).
15421545
///
15431546
/// If the process finished by calling `exit` with a nonzero value, this will return
15441547
/// that exit status.

0 commit comments

Comments
 (0)