Repository: tokio-rs/tokio
File: tokio/src/process/mod.rs (Rust)

Code before:
    /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
    /// let mut attribute_list = ProcThreadAttributeList::build()
    ///     .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
    ///     .finish()
    ///     .unwrap();
    ///
    /// let output = Command::new("ls")
    ///         .stdin(Stdio::null())
    ///         .stdout(Stdio::piped())
    ///         .stderr(Stdio::piped())
    ///         .spawn_with(|cmd| cmd.spawn_with_attributes(&attribute_list))
    ///         .unwrap()
    ///         .wait_with_output()
    ///         .await
    ///         .unwrap();
    /// # }
    /// ```
    pub fn spawn_with(
        &mut self,
        with: impl Fn(&mut StdCommand) -> io::Result<StdChild>,
    ) -> io::Result<Child> {
        imp::spawn_child_with(&mut self.std, with).map(|spawned_child| Child {
            child: FusedChild::Child(ChildDropGuard {
                inner: spawned_child.child,
                kill_on_drop: self.kill_on_drop,
            }),
            stdin: spawned_child.stdin.map(|inner| ChildStdin { inner }),
            stdout: spawned_child.stdout.map(|inner| ChildStdout { inner }),
            stderr: spawned_child.stderr.map(|inner| ChildStderr { inner }),
        })
    }

    /// Executes the command as a child process, waiting for it to finish and
    /// collecting its exit status.
    ///
    /// By default, stdin, stdout and stderr are inherited from the parent.
    /// If any input/output handles are set to a pipe then they will be immediately
    /// closed after the child is spawned.
    ///
    /// All I/O this child does will be associated with the current default
    /// event loop.
    ///
    /// The destructor of the future returned by this function will kill
    /// the child if [`kill_on_drop`] is set to true.
    ///
    /// [`kill_on_drop`]: fn@Self::kill_on_drop
    ///
    /// # Errors
    ///
    /// This future will return an error if the child process cannot be spawned
    /// or if there is an error while awaiting its status.

Review comment (suggestion):
We should probably gate this method behind `--cfg tokio_unstable`. Once `spawn_with_attributes` is stabilized, we will want to get rid of it again, but we can't do that if we stabilize this method.

Code after:
    /// let parent_process_handle = parent.raw_handle();
    ///
    /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
    /// let attribute_list = ProcThreadAttributeList::build()
    ///     .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
    ///     .finish()
    ///     .unwrap();
    ///
    /// let _output = Command::new("ls")
    ///     .stdin(Stdio::null())
    ///     .stdout(Stdio::piped())
    ///     .stderr(Stdio::piped())
    ///     .spawn_with(|cmd| cmd.spawn_with_attributes(&attribute_list))
    ///     .unwrap()
    ///     .wait_with_output()
    ///     .await
    ///     .unwrap();
    /// # }
    /// ```
    #[cfg(tokio_unstable)]
    #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
    #[inline]
    pub fn spawn_with(
        &mut self,
        with: impl Fn(&mut StdCommand) -> io::Result<StdChild>,
    ) -> io::Result<Child> {
        // On two lines to circumvent a mutable borrow check failure.
        let child = with(&mut self.std)?;
        self.build_child(child)
    }

    /// Small indirection for the spawn implementations.
    ///
    /// This is introduced for [`Self::spawn`] and [`Self::spawn_with`] to use:
    /// [`Self::spawn`] cannot depend directly on on [`Self::spawn_with`] since
    /// it is behind `tokio_unstable`. It also serves as a way to reduce
    /// monomorphization bloat by taking in an already-spawned child process
    /// instead of a command and custom spawn function.
    fn build_child(&self, child: StdChild) -> io::Result<Child> {
        let spawned_child = imp::build_child(child)?;

        Ok(Child {
            child: FusedChild::Child(ChildDropGuard {
                inner: spawned_child.child,
                kill_on_drop: self.kill_on_drop,
            }),
            stdin: spawned_child.stdin.map(|inner| ChildStdin { inner }),
            stdout: spawned_child.stdout.map(|inner| ChildStdout { inner }),
            stderr: spawned_child.stderr.map(|inner| ChildStderr { inner }),
        })
    }