pipeop 0.1.8

Adding the pipe operator to Rust with a declarative macro.
Documentation

The pipe operator in Rust

This crate is exactly what you expect it to be, the pipe operator in Rust. It's very simple, but effective nonetheless.

Usage

fn println(message: String) {
    println!("{message}");
}

fn greet(name: &'static str) -> String {
    format!("Hello, {name}!")
}

pipe!("David" // any expression
    |> greet
    |> println
);

Partial invocation of pipes

You can partially invoke pipes, the @ token will be replaced by the value currently going through the pipeline. The @ token can be in any position, not just at the start or end.

fn println(message: &'static str, upcase: bool) {
    let message = match upcase {
        true => message.to_uppercase(),
        false => message.to_string(),
    };

    println!("{message}");
}

pipe!("Hello" |> println(@, true)); // will output "HELLO" to stdout

Invoking methods on the item in the pipeline

You can invoke methods on the item in the pipeline at any time by prefixing the method identifier by a .

fn println(message: String) {
    println!("{message}");
}

// This is functionally the same as the "Partial invocation" example.
pipe!("Hello" 
    |> .to_uppercase
    |> println
);

Closure based pipes

You can also use closures as pipes, so you don't have to define a whole new function for every simple operation.

Both types of closures are valid, you can have a closure that just evaluates an expression, or you can have a whole code block.

pipe!("Hello"
    |> .to_uppercase
    |> |value| println!("{value}")
);

Storing the pipeline in a reusable closure

To store a pipeline in a closure you can put ... where you would normally put the pipe's initial value.

let f = pipe!(... as &'static str |> .to_uppercase);

f("Hello"); // HELLO

Note: often the type of the item can be inferred, in which case you can omit the as type part