conch-runtime-pshaw 0.1.6

A library for evaluating/executing programs written in the shell programming language.
Documentation
use crate::env::{
    AsyncIoEnvironment, FileDescEnvironment, FileDescOpener, Pipe, ReportErrorEnvironment,
    SubEnvironment,
};
use crate::io::Permissions;
use crate::spawn::subshell::subshell_with_env;
use crate::{Spawn, STDOUT_FILENO};
use std::borrow::Cow;
use std::error::Error;
use std::future::Future;
use std::io;

/// Spawns something whose standard output will be captured (and trailing newlines trimmed).
pub fn substitution<S, E>(spawn: S, env: &E) -> impl Future<Output = Result<String, S::Error>>
where
    S: Spawn<E>,
    S::Error: 'static + Send + Sync + From<io::Error> + Error,
    E: AsyncIoEnvironment
        + FileDescEnvironment
        + FileDescOpener
        + ReportErrorEnvironment
        + SubEnvironment,
    E::FileHandle: From<E::OpenedFileHandle>,
    E::IoHandle: From<E::OpenedFileHandle>,
{
    let mut env = env.sub_env();
    async move {
        let Pipe {
            reader: cmd_output,
            writer: cmd_stdout_fd,
        } = env.open_pipe()?;

        let cmd_stdout_fd: E::FileHandle = cmd_stdout_fd.into();
        env.set_file_desc(STDOUT_FILENO, cmd_stdout_fd, Permissions::Write);

        let output = env.read_all(cmd_output.into());
        let cmd = subshell_with_env(spawn, env);

        let (buf, _) = futures_util::join!(output, cmd);
        let mut buf = buf?;

        while Some(&b'\n') == buf.last() {
            buf.pop();
            if Some(&b'\r') == buf.last() {
                buf.pop();
            }
        }

        let ret = match String::from_utf8_lossy(&buf) {
            Cow::Owned(s) => s,
            Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(buf) },
        };

        Ok(ret)
    }
}