#![cfg_attr(test, feature(macro_metavar_expr))]
#![no_std]
#![doc = include_str!("../README.md")]
#[macro_export]
macro_rules! pipe {
($e:expr) => { $e };
($in:expr => $($i:ident).+ $(())? $(=> $($tail:tt)+)?) => {
pipe!($($i).+($in) $(=> $($tail)+)?)
};
($in:expr => $($i:ident).+ ($($($arg_head:expr_2021),*,)? $(_ $(, $arg_tail:expr_2021)*),*) $(=> $($tail:tt)+)?) => {
{
let pipe_temp = $in; pipe!($($i).+($($($arg_head),*,)? $(pipe_temp $(, $arg_tail)*),*) $(=> $($tail)+)?)
}
};
($in:expr => ($e:expr) ($($($arg_head:expr_2021),*,)? $(_ $(, $arg_tail:expr_2021)*),*) $(=> $($tail:tt)+)?) => {
{
let pipe_temp = $in; pipe!($e($($($arg_head),*,)? $(pipe_temp $(, $arg_tail)*),*) $(=> $($tail)+)?)
}
};
($in:expr => $e:expr $(=> $($tail:tt)+)?) => {
pipe!($e($in) $(=> $($tail)+)?)
};
}
#[cfg(test)]
mod tests {
#[test]
fn test_simple() {
fn test(x: u16) -> f32 {
f32::from(x + 1)
}
fn test2(x: f32) -> f32 {
x + 1.
}
let x = 3;
assert_eq!(pipe!(x+1 => test => test2), test2(test(x + 1)));
assert_eq!(pipe!(x+1 => test() => test2()), test2(test(x + 1)));
}
#[test]
fn test_underscore_fill() {
fn test(x: u16) -> u16 {
x
}
fn test2(x: u16, y: u16) -> (u16, u16) {
(x, y)
}
let x = 3;
let y = 4;
assert_eq!(pipe!(x-1 => test => test2(_, y)), test2(test(x - 1), y));
assert_eq!(pipe!(x-1 => test => test2(y, _)), test2(y, test(x - 1),));
assert_eq!(
pipe!(x-1 => test => test2(_, _)),
test2(test(x - 1), test(x - 1))
);
}
#[test]
fn test_associated_functions() {
fn test(x: u16) -> u16 {
x + 1
}
let x = 3;
assert_eq!(
pipe!(x-2 => test => u16::to_be => u16::isqrt),
u16::isqrt(u16::to_be(test(x - 2)))
);
}
#[test]
fn test_methods() {
fn test(x: u16) -> u16 {
x + 1
}
let x = 3;
let y = 4;
assert_eq!(
pipe!(x+2 => test => y.max => test),
test(y.max(test(x + 2)))
);
let mut y = None;
assert_eq!(
pipe!(x+2 => y.map_or(_, |x| x + 2) => test),
test(y.map_or(x + 2, |x| x + 2))
);
y = Some(x + 2);
assert_eq!(
pipe!(x+2 => y.map_or(_, |x| x + 2) => test),
test(y.map_or(x + 2, |x| x + 2))
);
}
#[test]
fn test_lambdas() {
fn test(x: u16) -> u16 {
x + 1
}
let x = 3;
assert_eq!(
pipe!(x => test => |x| {x - 2} => test),
test((|x| { x - 2 })(test(x)))
);
}
#[test]
fn test_macros() {
use paste::paste;
macro_rules! bind {
($($f:ident).+ ($($($head:expr_2021),*,)? $(_ $(, $tail:expr_2021)*),*)) => {
paste! {
|$([<x ${index()}>] $(${ignore($tail)})*),+| {
$($f).+($($($head),*,)? $([<x ${index()}>] $(, $tail)*),*)
}
}
};
($($f:ident).+ ($($head:expr_2021),*)) => {
|| {
$($f).+($($head),*)
}
};
}
fn test(x: u16, y: u16, z: u16) -> (u16, u16, u16) {
(x, y, z)
}
let x = 1;
let y = 2;
let z = 3;
assert_eq!(pipe!(x => bind!(test(_, y, z))), test(x, y, z));
assert_eq!(pipe!(y => bind!(test(x, _, z))), test(x, y, z));
assert_eq!(pipe!(x => (bind!(test(_, _, z))) (_, _)), test(x, x, z));
}
}