/// * No arguments to the program
/// * Inherit the current process's environment
/// * Inherit the current process's working directory
- /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
+ /// * Inherit stdin/stdout/stderr for [`spawn`] or [`status`], but create pipes for [`output`]
+ ///
+ /// [`spawn`]: Self::spawn
+ /// [`status`]: Self::status
+ /// [`output`]: Self::output
///
/// Builder methods are provided to change these defaults and
/// otherwise configure the process.
/// Configuration for the child process's standard input (stdin) handle.
///
- /// Defaults to [`inherit`] when used with `spawn` or `status`, and
- /// defaults to [`piped`] when used with `output`.
+ /// Defaults to [`inherit`] when used with [`spawn`] or [`status`], and
+ /// defaults to [`piped`] when used with [`output`].
///
/// [`inherit`]: Stdio::inherit
/// [`piped`]: Stdio::piped
+ /// [`spawn`]: Self::spawn
+ /// [`status`]: Self::status
+ /// [`output`]: Self::output
///
/// # Examples
///
/// Configuration for the child process's standard output (stdout) handle.
///
- /// Defaults to [`inherit`] when used with `spawn` or `status`, and
- /// defaults to [`piped`] when used with `output`.
+ /// Defaults to [`inherit`] when used with [`spawn`] or [`status`], and
+ /// defaults to [`piped`] when used with [`output`].
///
/// [`inherit`]: Stdio::inherit
/// [`piped`]: Stdio::piped
+ /// [`spawn`]: Self::spawn
+ /// [`status`]: Self::status
+ /// [`output`]: Self::output
///
/// # Examples
///
/// Configuration for the child process's standard error (stderr) handle.
///
- /// Defaults to [`inherit`] when used with `spawn` or `status`, and
- /// defaults to [`piped`] when used with `output`.
+ /// Defaults to [`inherit`] when used with [`spawn`] or [`status`], and
+ /// defaults to [`piped`] when used with [`output`].
///
/// [`inherit`]: Stdio::inherit
/// [`piped`]: Stdio::piped
+ /// [`spawn`]: Self::spawn
+ /// [`status`]: Self::status
+ /// [`output`]: Self::output
///
/// # Examples
///
/// .status()
/// .expect("failed to execute process");
///
- /// println!("process finished with: {}", status);
+ /// println!("process finished with: {status}");
///
/// assert!(status.success());
/// ```
/// For proper error reporting of failed processes, print the value of `ExitStatus` or
/// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display).
///
+/// # Differences from `ExitStatus`
+///
+/// `ExitCode` is intended for terminating the currently running process, via
+/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
+/// termination of a child process. These APIs are separate due to platform
+/// compatibility differences and their expected usage; it is not generally
+/// possible to exactly reproduce an ExitStatus from a child for the current
+/// process after the fact.
+///
/// [`status`]: Command::status
/// [`wait`]: Child::wait
//
/// .status()
/// .expect("ls could not be executed");
///
- /// println!("ls: {}", status);
+ /// println!("ls: {status}");
/// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
/// # } // cfg!(unix)
/// ```
/// if status.success() {
/// println!("'projects/' directory created");
/// } else {
- /// println!("failed to create 'projects/' directory: {}", status);
+ /// println!("failed to create 'projects/' directory: {status}");
/// }
/// ```
#[must_use]
/// .expect("failed to execute mkdir");
///
/// match status.code() {
- /// Some(code) => println!("Exited with status code: {}", code),
+ /// Some(code) => println!("Exited with status code: {code}"),
/// None => println!("Process terminated by signal")
/// }
/// ```
#[unstable(feature = "exit_status_error", issue = "84908")]
impl crate::error::Error for ExitStatusError {}
-/// This type represents the status code a process can return to its
-/// parent under normal termination.
+/// This type represents the status code the current process can return
+/// to its parent under normal termination.
+///
+/// `ExitCode` is intended to be consumed only by the standard library (via
+/// [`Termination::report()`]), and intentionally does not provide accessors like
+/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the
+/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From<u8> for
+/// ExitCode` for constructing other arbitrary exit codes.
+///
+/// # Portability
///
/// Numeric values used in this type don't have portable meanings, and
/// different platforms may mask different amounts of them.
/// [`SUCCESS`]: ExitCode::SUCCESS
/// [`FAILURE`]: ExitCode::FAILURE
///
-/// **Warning**: While various forms of this were discussed in [RFC #1937],
-/// it was ultimately cut from that RFC, and thus this type is more subject
-/// to change even than the usual unstable item churn.
+/// # Differences from `ExitStatus`
+///
+/// `ExitCode` is intended for terminating the currently running process, via
+/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
+/// termination of a child process. These APIs are separate due to platform
+/// compatibility differences and their expected usage; it is not generally
+/// possible to exactly reproduce an ExitStatus from a child for the current
+/// process after the fact.
+///
+/// # Examples
+///
+/// `ExitCode` can be returned from the `main` function of a crate, as it implements
+/// [`Termination`]:
+///
+/// ```
+/// use std::process::ExitCode;
+/// # fn check_foo() -> bool { true }
+///
+/// fn main() -> ExitCode {
+/// if !check_foo() {
+/// return ExitCode::from(42);
+/// }
///
-/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937
+/// ExitCode::SUCCESS
+/// }
+/// ```
#[derive(Clone, Copy, Debug)]
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.61.0")]
pub struct ExitCode(imp::ExitCode);
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.61.0")]
impl ExitCode {
- /// The canonical ExitCode for successful termination on this platform.
+ /// The canonical `ExitCode` for successful termination on this platform.
///
/// Note that a `()`-returning `main` implicitly results in a successful
/// termination, so there's no need to return this from `main` unless
/// you're also returning other possible codes.
- #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+ #[stable(feature = "process_exitcode", since = "1.61.0")]
pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS);
- /// The canonical ExitCode for unsuccessful termination on this platform.
+ /// The canonical `ExitCode` for unsuccessful termination on this platform.
///
/// If you're only returning this and `SUCCESS` from `main`, consider
/// instead returning `Err(_)` and `Ok(())` respectively, which will
/// return the same codes (but will also `eprintln!` the error).
- #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+ #[stable(feature = "process_exitcode", since = "1.61.0")]
pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
}
impl ExitCode {
- // This should not be stabilized when stabilizing ExitCode, we don't know that i32 will serve
+ // This is private/perma-unstable because ExitCode is opaque; we don't know that i32 will serve
// all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we
// likely want to isolate users anything that could restrict the platform specific
// representation of an ExitCode
//
// More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426
- /// Convert an ExitCode into an i32
- #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+ /// Convert an `ExitCode` into an i32
+ #[unstable(
+ feature = "process_exitcode_internals",
+ reason = "exposed only for libstd",
+ issue = "none"
+ )]
#[inline]
+ #[doc(hidden)]
pub fn to_i32(self) -> i32 {
self.0.as_i32()
}
}
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.61.0")]
impl From<u8> for ExitCode {
- /// Construct an exit code from an arbitrary u8 value.
+ /// Construct an `ExitCode` from an arbitrary u8 value.
fn from(code: u8) -> Self {
ExitCode(imp::ExitCode::from(code))
}
/// let mut child = Command::new("ls").spawn().unwrap();
///
/// match child.try_wait() {
- /// Ok(Some(status)) => println!("exited with: {}", status),
+ /// Ok(Some(status)) => println!("exited with: {status}"),
/// Ok(None) => {
/// println!("status not ready yet, let's really wait");
/// let res = child.wait();
- /// println!("result: {:?}", res);
+ /// println!("result: {res:?}");
/// }
- /// Err(e) => println!("error attempting to wait: {}", e),
+ /// Err(e) => println!("error attempting to wait: {e}"),
/// }
/// ```
#[stable(feature = "process_try_wait", since = "1.18.0")]
/// std::process::exit(match run_app() {
/// Ok(_) => 0,
/// Err(err) => {
-/// eprintln!("error: {:?}", err);
+/// eprintln!("error: {err:?}");
/// 1
/// }
/// });
///
/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
+///
+/// Because different runtimes have different specifications on the return value
+/// of the `main` function, this trait is likely to be available only on
+/// standard library's runtime for convenience. Other runtimes are not required
+/// to provide similar functionality.
#[cfg_attr(not(test), lang = "termination")]
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
#[rustc_on_unimplemented(
message = "`main` has invalid return type `{Self}`",
label = "`main` can only return types that implement `{Termination}`"
pub trait Termination {
/// Is called to get the representation of the value as status code.
/// This status code is returned to the operating system.
+ #[stable(feature = "termination_trait_lib", since = "1.61.0")]
fn report(self) -> ExitCode;
}
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
impl Termination for () {
#[inline]
fn report(self) -> ExitCode {
}
}
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
impl<E: fmt::Debug> Termination for Result<(), E> {
fn report(self) -> ExitCode {
match self {
}
}
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
impl Termination for ! {
fn report(self) -> ExitCode {
self
}
}
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
impl<E: fmt::Debug> Termination for Result<!, E> {
fn report(self) -> ExitCode {
let Err(err) = self;
- eprintln!("Error: {:?}", err);
+ eprintln!("Error: {err:?}");
ExitCode::FAILURE.report()
}
}
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
impl<E: fmt::Debug> Termination for Result<Infallible, E> {
fn report(self) -> ExitCode {
let Err(err) = self;
}
}
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
impl Termination for ExitCode {
#[inline]
fn report(self) -> ExitCode {