1个不稳定版本
0.1.0 | 2020年5月22日 |
---|
#1091 in 进程宏
24KB
456 代码行
使函数部分应用的宏
示例
// Simple function
fn add(x: u32, y: u32) -> i64 {
(x + y) as i64
}
fn main() {
println!("add: {}",add(1,2));
}
想法是定义一个宏,将一个函数转换成一个支持部分应用的结构的宏。这会看起来像这样
#[part_app]
fn add(x: u32, y: u32) -> i64 {
(x + y) as i64
}
fn main() {
let a = add();
let two = a.x(|| 2);
let number = two.y(|| 40);
assert_eq!(number.call(), 42);
}
#[part_app]
会展开成类似这样(为了简洁进行了编辑)。
struct add___Added;
struct add___Empty;
struct __PartialApplication__add_<x, x___FN, y, y___FN, BODYFN>
where
xFN: FnOnce() -> u32,
yFN: FnOnce() -> u32,
BODYFN: FnOnce(u32, u32) -> i64,
{
xm: ::std::marker::PhantomData<x>,
ym: ::std::marker::PhantomData<y>,
x: Option<xFN>,
y: Option<yFN>,
body: BODYFN,
}
fn add<x, y>(
) -> __PartialApplication__add_<addEmpty, x, addEmpty, y, impl FnOnce(u32, u32) -> i64>
where
x: FnOnce() -> u32,
y: FnOnce() -> u32,
{
__PartialApplication__add_ {
x: None,
y: None,
xm: ::std::marker::PhantomData,
ym: ::std::marker::PhantomData,
body: |x, y| (x + y) as i64,
}
}
impl<xFN: FnOnce() -> u32, yFN: FnOnce() -> u32, BODYFN: FnOnce(u32, u32) -> i64, y>
__PartialApplication__add_<addEmpty, xFN, y, yFN, BODYFN>
{
fn x(
mut self,
x: xFN,
) -> __PartialApplication__add_<addAdded, xFN, y, yFN, BODYFN> {
self.x = Some(x);
unsafe {
::std::mem::transmute_copy::<
__PartialApplication__add_<addEmpty, xFN, y, yFN, BODYFN>,
__PartialApplication__add_<addAdded, xFN, y, yFN, BODYFN>,
>(&self)
}
}
}
impl<xFN: FnOnce() -> u32, yFN: FnOnce() -> u32, BODYFN: FnOnce(u32, u32) -> i64, x>
__PartialApplication__add_<x, xFN, addEmpty, yFN, BODYFN>
{
fn y(
mut self,
y: yFN,
) -> __PartialApplication__add_<x, xFN, addAdded, yFN, BODYFN> {
self.y = Some(y);
unsafe {
::std::mem::transmute_copy::<
__PartialApplication__add_<x, xFN, addEmpty, yFN, BODYFN>,
__PartialApplication__add_<x, xFN, addAdded, yFN, BODYFN>,
>(&self)
}
}
}
impl<xFN: FnOnce() -> u32, yFN: FnOnce() -> u32, BODYFN: FnOnce(u32, u32) -> i64>
__PartialApplication__add_<addAdded, xFN, addAdded, yFN, BODYFN>
{
fn call(self) -> i64 {
(self.body)(self.x.unwrap()(), self.y.unwrap()())
}
}
重要的是,这将是一个零成本抽象。理论上,Option
将被移除,因为它们没有进行检查。FnOnce
可以被优化掉(因为它只是编译器操作语法树),所以结构体不持有任何不可优化的数据。这意味着它的大小应该是0,因此它将被优化掉。
它的工作原理
宏创建了一个函数,该函数生成一个类似于构建器模式的结构体。结构体由已定义的变量进行参数化。只有当变量未定义时,才会为结构体实现变量的定义。最终的调用仅当每个变量都已定义时才会定义。当其位置参数为Added
类型时,变量被标记为已定义。当其位置由Empty
类型参数化时,它被标记为未定义。
限制
为了尽可能优化,我避免了任何堆分配。这阻止了我抽象闭包的类型。任何PartialApplication结构体的实例只能持有一种类型的闭包。这也阻止了复制。为了解决这个问题,添加了poly
属性以启用堆分配,从而使具有相同特质的所有闭包都同样可接受。属性Clone
允许在调用之前克隆部分构造的函数。value
允许传入值而不是结构体。
依赖项
~1.5MB
~36K SLoC