Skip to content

pimalaya/process

Repository files navigation

⚙ process Matrix

Set of Rust libraries to manage processes.

Why?

Designing a generic API for a library that relies on I/O is a real challenge. This project tries to solve that matter by abstracting away the I/O:

  • The core lib exposes I/O-free, composable and iterable state machines (named flows)
  • The I/O connector executes I/O everytime a flow Iterator produces an I/O request
let mut flow = Flow::new()
let conn = IoConnector::new();

while let Some(io) = flow.next() {
    conn.execute(&mut flow, io)?;
}

let output = flow.output()

sans-io

When?

✔ If you develop a library that relies on processes, then process-lib might help you.

✔ If you develop an application that uses process-lib flows, any I/O connector might help you. If you do not find the right built-in connector matching your needs, you can easily build your own. PRs are welcomed!

✘ If you develop an application without process-lib, then this project might not help you. Just use directly the process module matching your environment (std::process, tokio::process etc).

Structure

  • process-lib: a set of I/O-free tools to deal with processes
  • process-std: a standard, blocking I/O connector for process-lib
  • process-tokio: Tokio-based, async I/O connector for process-lib

Examples

Spawn blocking process then wait for status

use process_lib::{Command, SpawnCommandThenWait};
use process_std::Connector;

fn main() {
    let conn = Connector::new();

    let mut command = Command::new("echo");
    command.arg("hello");
    command.arg("world");

    let mut flow = SpawnCommandThenWait::new(command);

    while let Some(io) = flow.next() {
        conn.execute(&mut flow, io).unwrap();
    }

    let status = flow.take_status().unwrap();
    println!("status: {status:#?}");

    // status: ExitStatus(
    //     unix_wait_status(
    //         0,
    //     ),
    // )
}

Spawn Tokio process then wait for output

use process_lib::{Command, SpawnCommandThenWaitWithOutput};
use process_tokio::Connector;

fn main() {
    let conn = Connector::new();

    let mut command = Command::new("echo");
    command.arg("hello");
    command.arg("world");

    let mut flow = SpawnCommandThenWaitWithOutput::new(command);

    while let Some(io) = flow.next() {
        conn.execute(&mut flow, io).await.unwrap();
    }

    let output = flow.take_output().unwrap();
    println!("output: {output:#?}");

    // output: Output {
    //     status: ExitStatus(
    //         unix_wait_status(
    //             0,
    //         ),
    //     ),
    //     stdout: "hello world\n",
    //     stderr: "",
    // }
}

Create a pipeline

use std::process::Stdio;

use process_lib::{Command, SpawnCommandThenWait, SpawnCommandThenWaitWithOutput};
use process_std::Connector;

fn main() {
    let conn = Connector::new();

    let mut command = Command::new("echo");
    command.arg("hello");
    command.arg("world");
    command.stdout(Stdio::piped());

    let mut flow = SpawnCommandThenWait::new(command);

    while let Some(io) = flow.next() {
        conn.execute(&mut flow, io).unwrap();
    }

    let stdout = flow.take_stdout().unwrap();

    // move stdout from previous command to next command stdin

    let mut command = Command::new("cat");
    command.arg("-E");
    command.stdin(stdout);

    let mut flow = SpawnCommandThenWaitWithOutput::new(command);

    while let Some(io) = flow.next() {
        conn.execute(&mut flow, io).unwrap();
    }

    let output = flow.take_output().unwrap();
    println!("output: {output:#?}");

    // output: Output {
    //     status: ExitStatus(
    //         unix_wait_status(
    //             0,
    //         ),
    //     ),
    //     stdout: "hello world$\n",
    //     stderr: "",
    // }
}

See more examples at process-std/examples and process-tokio/examples.

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that helped the project to receive financial support from various programs:

If you appreciate the project, feel free to donate using one of the following providers:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal