macro_rules! pipe {
{ @CALL [ $($f:tt)* ] [ $($value:expr),* ] } => { ... };
{
@CALL
$f:tt
$value:tt => $args:tt
} => { ... };
{ // 终态:插入完成
@INSERT
[ $($f:tt)* ]
$_value:tt =>
[
$( $values:expr ),*
$(,)?
]
} => { ... };
{ // 中态:不断插入
@INSERT
$f:tt
[ $value:expr ] =>
[
$( $value_past:expr, )*
_
$( $tail:tt )*
]
} => { ... };
{ $value:expr } => { ... };
{
$value:expr =>
#{ $($prefix:tt)* }
$( => $($tail:tt)*)?
} => { ... };
{
$value:expr =>
{ $($suffix:tt)* }#
$( => $($tail:tt)*)?
} => { ... };
{
$value:expr =>
. $key:tt $( ( $($param:tt)* ) )?
$( => $($tail:tt)*)?
} => { ... };
{
$value:expr =>
[ $($dot_path:tt).+ ] $( ( $($param:tt)* ) )?
$( => $($tail:tt)*)?
} => { ... };
{
$value:expr =>
$($p:tt)::+ $( ( $($param:tt)* ) )?
$( => $($tail:tt)*)?
} => { ... };
{
$value:expr =>
($f:expr) $( ( $($param:tt)* ) )?
$( => $($tail:tt)*)?
} => { ... };
}Expand description
§pipe!
一个实用、强大而高效的「管道」宏,允许带任意数量插值的任意函数调用
- 🎯用以实现类似Julia
@pipe的「管道处理」效果 - 📌使用占位符
_进行插值- ✅允许多重插值——但会复制整个表达式
- ✨部分灵感来自Julia的Pipe.jl
- 📄其中的宏
@pipe有类似的效果
- 📄其中的宏
- ⚠️【2024-03-26 00:16:36】目前对「完全限定语法」尚未有良好兼容
- 📄
Vec::<usize>::new会因「大于/小于 符号」失效 - ✅可使用「代码后缀」语法模拟,但其中不提供插值
- 📄如
=> {.collect::<Vec<_>>()}#
- 📄如
- 📄
§📄示例 Examples
use nar_dev_utils::{pipe, asserts};
fn f1(x: i32) -> i32 { x + 1 }
fn f2(x: i32, y: i32) -> i32 { x + y }
fn f3(x: i32, y: i32) -> i32 { x - y }
let v = 1;
let x = 2;
let y = 3;
// (((x + 1) + 2) - 3)
let piped = pipe! { v => f1 => f2(x, _) => (f3)(_, y) => f2(_, _) };
let normal = f2(f3(f2(x, f1(v)), y), f3(f2(x, f1(v)), y));
asserts!{
piped => normal,
piped => 2,
};§🚩内部实现
- 📌递归模型:标签树撕咬机 + 多分派状态机
- 总体流程:用户输入 ⇒ 内部输入 ⇒ 单次管道返回值 ⇒ 尾递归回代
- 📌对「被管道的函数」的语法支持
标识符#{前缀}.属性.方法(..参数)(表达式)模块::函数[对象.方法]
§✅规模化测试
use nar_dev_utils::{pipe, asserts};
mod m {
pub fn add_one(x: i32) -> i32 {
x + 1
}
pub fn tri_add(x: i32, y: i32, z: i32) -> i32 {
x + y + z
}
}
use m::add_one;
asserts! {
// 内部情形
pipe! {@CALL [add_one] [1]} => 2,
pipe! {@CALL [i32::checked_add] [1] => [_, 2]} => Some(3),
pipe! {@CALL [m::tri_add] [1] => [_, 2, 3]} => 6,
pipe! {@CALL [m::tri_add] [2] => [1, _, 3]} => 6,
pipe! {@CALL [m::tri_add] [3] => [1, 2, _]} => 6,
// 平凡情况:单个值 //
pipe! { 1 } => 1,
pipe! { 1 + 1 } => 2,
pipe! { add_one(1) } => 2,
pipe! { match 1 { 1 => 2, _ => 0 } } => 2,
// 最简单的情况:单函数 //
// 直接使用标识符
pipe! {1 => add_one} => 2,
// 模块路径
pipe! {1 => m::add_one} => 2,
// 关联函数
pipe! {&vec![1] => Vec::len} => 1,
// 内部使用闭包的表达式
pipe! {1 => (|x| x + 1)} => 2,
// 对象的方法
pipe! {1 => [0_i32.min]} => 0,
// 实用辅助:借用、访问 //
// 测试`self.method`
pipe! {
"I can be turned into a &str!"
=> String::from // 转换成字符串
=> #{&} // 加上前缀`&`转换为`&String`
=> .as_str() // 转换为`&str`
=> .to_lowercase() // 全小写
} => "i can be turned into a &str!",
// 测试`self.field`、`&mut`
{
let mut s_0 = ("Hello, ".to_string(), 0);
pipe! {
s_0
=> .0 // 获取内部的`String`
=> #{&mut} // 获取`&mut String`
=> .push_str("pipe!") // 追加字符串
};
s_0.0
} => "Hello, pipe!",
// 实用辅助:数组索引、上抛、后缀运算 //
// 测试`self[i]`
pipe! {
["this", "is", "an", "array"]
=> {[3]}# // 索引第三个元素
=> .to_uppercase() // 全大写
} => "ARRAY",
// 测试`self?`、`self+1`
{
fn parse_and_add_one(input: impl AsRef<str>) -> Result<usize, std::num::ParseIntError> {
pipe! {
input
=> .as_ref() // 先转成字符串引用
=> (str::parse::<usize>) // 再调用「解析」方法
=> {?}# // 解析失败时,上抛错误
=> {+1}# // 后缀`+1`
=> Result::Ok // 包装进Result中
}
}
// 检验处理过程
(parse_and_add_one("1").unwrap(), parse_and_add_one("err"))
} => (2, "err".parse::<usize>()),
// 复杂情况:函数插值 //
// 单重插值语法
pipe! {1 => i32::checked_add(_, 1)} => Some(2),
pipe! {1 => i32::min(0, _)} => 0,
pipe! {1 => (|x, y| x + y)(_, 1)} => 2,
pipe! {1 => (|x, y, z| x * y * z)(1, _, 2)} => 2,
// 多重插值语法 | 直接拷贝表达式
pipe! { @INSERT [usize::checked_add] [1] => [2, 3] } => Some(5)
pipe! { @INSERT [m::tri_add] [1] => [_, _, 3] } => 5
pipe! { @INSERT [m::tri_add] [2] => [1, _, _] } => 5
pipe! { @INSERT [m::tri_add] [3] => [_, 2, _] } => 8
pipe! { @INSERT [usize::checked_add] [0] => [_, _] } => Some(0)
pipe! { @CALL [usize::checked_add] [0] => [_, _] } => Some(0)
// 复杂情况:多函数链路 //
// 直接使用标识符
pipe! {1 => add_one => add_one} => 3,
// 模块路径
pipe! {1 => m::add_one => m::add_one} => 3,
// 关联函数
pipe! {&vec![1] => Vec::len => usize::checked_add(_, 1)} => Some(2),
// 内部使用闭包的表达式
pipe! {1 => (|x| x + 1) => (|x| x + 1)} => 3,
// 对象的方法
pipe! {1 => [0_i32.min] => [1_i32.max]} => 1,
// 大 杂 烩 //
pipe! {
// 最初的值
&vec![1]
// 关联函数
=> Vec::len // 1
// 内部使用闭包的表达式
=> (|x:usize| x as i32) // 转换类型
=> (|x| x + 1) // 2
// 内部使用闭包的表达式(带参数)
=> (|x, y| x - y)(_, 1) // 1
// 直接使用标识符
=> add_one // 2
// 模块路径
=> m::add_one // 3
// 关联函数(带参数)
=> i32::checked_sub(_, 1) // Some(2)
=> Option::unwrap // 2
// 对象的方法
=> [1_i32.min] // 1
=> [(-1_i32).max] // 1
} => 1
}