pipe{i}
pipei allows writing x.pipe(f)(y, z) in place of f(x, y, z), enabling method-style chaining and partial application for multi-argument functions.
It also provides tap and tap_with for multi-argument side effects that return the original value.
This project is inspired by the UMCS (Universal Method Call Syntax) proposal. It requires nightly Rust for #![feature(impl_trait_in_assoc_type)].
Basic Chaining
pipe passes the value as the first argument to a function and returns the result.
tap passes the value to a function for a side effect, then returns the original value.
use ;
let result = 2
.pipe
.pipe
.pipe;
assert_eq!;
let val = 2
.tap // Immutable: inferred &i32
.tap; // Mutable: inferred &mut i32
assert_eq!;
Partial Application
Because pipe returns a closure over the remaining arguments, it doubles as partial application.
use Pipe;
let season_pass = Discount ;
// Equivalent to (the hypothetical): let apply_discount = season_pass.apply;
let apply_discount = season_pass.pipe;
let prices = ;
let discounted = prices.map;
assert_eq!;
Projected Side Effects
tap_with lets you reuse a side-effect function whose signature doesn't match the receiver. A projection extracts the relevant part; if it returns Some, the side effect runs on the projected value. If None, it is skipped. In both cases, the original value is returned.
# use TapWith;
let mut req = Request ;
// track_retry expects &mut u32, not &mut Request — the projection bridges the gap
.tap_with;
assert_eq!;
// tap only on Err
let res = Err::
.tap_with;
assert_eq!;
// tap only in debug builds
let req = req.tap_with;
assert_eq!;
Error Handling
The tap crate provides single-argument pipe and tap traits.
pipei generalizes both to multi-argument functions, which particularly simplifies fallible pipelines where ? interacts poorly with closures.
Standard Rust:
The reading order is inverted ("inside-out"): save is written first, but executes last.
save;
Using tap
Since ? applies inside the closure, the closure returns a Result, forcing manual Ok wrapping and an extra ?.
load?
.pipe?
.pipe;
Using pipei:
load?
.pipe
.pipe;
Feature Flags
To optimize compile time, enable only the arities you need (from 0 up to 50).
Use up_to_N features (available in multiples of five) or enable individual arity features.
[]
= "*" # default: features = ["up_to_5"]
# pipei = { version = "*", features = ["up_to_20", "31"] }
# pipei = { version = "*", features = ["0", "1", "3", "4"] }