Crates.io | spipe |
lib.rs | spipe |
version | 0.1.0 |
created_at | 2025-06-15 13:31:53.093846+00 |
updated_at | 2025-06-15 13:31:53.093846+00 |
description | Smart pipe macro for chaining function/method calls, with unwrap, map, and and_then support |
homepage | |
repository | https://github.com/shitohana/spipe |
max_upload_size | |
id | 1713310 |
size | 35,441 |
spipe
β Smart Pipe Macro for Rustspipe
is a procedural macro that brings smart pipe operators into Rust. It allows
you to write expressive and readable transformation pipelines, inspired by
functional languages like Elixir or F#, but tailored to Rustβs type system and
ergonomics.
With spipe
, you can:
.map(...).and_then(...)?
soupWarning This project is in an early development stage. Bug reports, feature requests, and contributions are welcome!
Rust doesnβt have a native pipe (|>
) operator. While method chaining works well for
many cases, it falls short when:
spipe!
solves this with flexible, intuitive operators and value-routing logic.
Each line in a spipe!
pipeline begins with an operator. These dictate how the value
is forwarded.
Operator | Name | Behavior |
---|---|---|
=> |
Basic | Just pass the value to a function or method |
=>& |
AndThen | Like .and_then(...) on Result/Option |
=>@ |
Map | Like .map(...) on Result/Option |
=>? |
Try | Applies ? to propagate errors/None |
=>* |
Unwrap | Calls .unwrap() |
=>+ |
Clone | Clones the current value |
=># |
Apply | Performs a side effect (e.g. println! ), returns original value |
=>$ |
ApplyMut | Like Apply, but passes mutable reference |
π‘ Mnemonics:
&
- and_then
@
- mapping at the value
?
- try / propagate
*
- deref / unpack / unwrap
+
- clone
#
- debug / apply
Hereβs how you control what happens to the piped value:
Syntax | Operation |
---|---|
func or func() |
Call the function with the value as the sole argument |
func(arg2, arg3) |
Insert the piped value as the first argument |
func(arg1, (), arg3) |
Substitute () with the piped value |
.method() |
Call method on the value |
.method(arg2) |
Piped value is the receiver (self) |
|x| x**2 |
Apply closure to the piped value |
(Type) |
Call Type::from(value) |
(Type?) |
Call Type::try_from(value) |
(as Type) |
Convert using as |
... |
Just pass the value as-is (NoOp) |
Add to your Cargo.toml:
[dependencies]
spipe = "0.1" # Replace with latest version
Import the macro:
use spipe::spipe;
fn parse_number(s: &str) -> Result<i32, &'static str> {
s.parse().map_err(|_| "not a number")
}
fn double(n: i32) -> i32 {
n * 2
}
let input = "42";
let res = spipe!(
input
=> parse_number
=>& Ok
=>@ double
=>? (as f64)
=># |v| println!("final value: {}", v)
);
assert_eq!(res, 84.0);
fn square(n: i32) -> i32 { n * n }
let result = spipe!(
4
=># |v| println!("initial: {}", v)
=> square
=># |v| println!("squared: {}", v)
=> |x| x + 10
=># |v| println!("plus 10: {}", v)
);
assert_eq!(result, 26);
let mut result = String::from("hello");
spipe!(
result
=> .to_uppercase()
=>$ .push('!')
=># |s| println!("Final: {}", s)
);
assert_eq!(result, "HELLO!");
fn wrap_with_brackets(prefix: &str, content: &str, suffix: &str) -> String {
format!("{}{}{}", prefix, content, suffix)
}
let raw = "core";
let wrapped = spipe!(
raw
=> .to_string
=> .to_uppercase
=> .as_str
=> wrap_with_brackets("[", (), "]")
);
assert_eq!(wrapped, "[CORE]");
spipe!
helps you write cleaner, more expressive Rust code by:
Wrapping up common Option/Result
logic
Unifying function, method, and closure syntax
Removing nested, noisy chains
Keeping logic readable and flat
This project is in early development, and your input matters! Ideas, bugs, PRs, new pipe operators β all welcome.
MIT or Apache-2.0 β your choice.