#![no_std]
#[macro_export]
macro_rules! partial {
(@inner [(() $id:expr) ($($cl_arg:ident),*) ($($fn_arg:expr),*)] ()) => {
|$($cl_arg),*| $id($($fn_arg),*);
};
(@inner [(move $id:expr) ($($cl_arg:ident),*) ($($fn_arg:expr),*)] ()) => {
move |$($cl_arg),*| $id($($fn_arg),*);
};
(@inner [$pt:tt ($($cl_arg:ident),*) ($($fn_arg:expr),*)] (_ , $($m_arg:tt)*) ) => {
partial!(
@inner [$pt ($($cl_arg,)* a) ($($fn_arg,)* a)] ($($m_arg)*)
)
};
(@inner [$pt:tt ($($cl_arg:ident),*) ($($fn_arg:expr),*)] (_) ) => {
partial!(
@inner [$pt ($($cl_arg,)* a) ($($fn_arg,)* a)] ()
)
};
(@inner [$pt:tt $cl_args:tt ($($fn_arg:expr),*)] ($e:expr , $($m_arg:tt)*) ) => {
partial!(
@inner [$pt $cl_args ($($fn_arg,)* $e)] ($($m_arg)*)
)
};
(@inner [$pt:tt $cl_args:tt ($($fn_arg:expr),*)] ($e:expr) ) => {
partial!(
@inner [$pt $cl_args ($($fn_arg,)* $e)] ()
)
};
(move $id:expr , $($args:tt)*) => {
partial!(@inner [(move $id) () ()] ($($args)*))
};
(move $id:expr ; $($args:tt)*) => {
partial!(@inner [(move $id) () ()] ($($args)*))
};
(move $id:expr => $($args:tt)*) => {
partial!(@inner [(move $id) () ()] ($($args)*))
};
($id:expr , $($args:tt)*) => {
partial!(@inner [(() $id) () ()] ($($args)*))
};
($id:expr ; $($args:tt)*) => {
partial!(@inner [(() $id) () ()] ($($args)*))
};
($id:expr => $($args:tt)*) => {
partial!(@inner [(() $id) () ()] ($($args)*))
};
}
#[cfg(test)]
mod test {
#[allow(unused)]
#[rustfmt::skip]
fn high_arity(
_: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (),
_: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (),
_: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (),
_: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (),
_: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (), _: (),
_: (), _: ()
) {
let c = partial!(high_arity,
(), (), (), (), (), (), (), (), (), (), (), (),
(), (), (), (), (), (), (), (), (), (), (), (),
(), (), (), (), (), (), (), (), (), (), (), (),
(), (), (), (), (), (), (), (), (), (), (), (),
(), (), (), (), (), (), (), (), (), (), (), (),
(), ()
);
}
#[test]
fn argument_order() {
fn foo(a: u32, b: u32) -> u32 {
100 + a - b
}
for i in 0..10 {
for j in 0..10 {
assert_eq!(foo(i, j), partial!(foo => i, _)(j));
}
}
}
#[test]
fn interspersed_expr_and_forwarders() {
fn foo(a: bool, b: bool, c: bool, d: bool, e: bool, f: bool) -> u8 {
fn shift(b: bool, n: usize) -> u8 {
(b as u8) << n
}
[f, e, d, c, b, a]
.iter()
.cloned()
.enumerate()
.fold(0, |acc, (n, arg)| acc | shift(arg, n))
}
let reduced_foo = partial!(foo => true, _, _, true, true, _);
assert_eq!(reduced_foo(false, false, false), 0b100110);
}
}
#[allow(unused)]
struct MoveCompileFail;
#[cfg(test)]
#[allow(unused)]
fn syntax_check() {
partial!(::core::option::Option::<i32>::is_some => _ );
#[derive(Clone)]
struct NoCopy;
fn foo(_: u8, _: u8, _: u8, _: u8, _: u8, _: u8, _: NoCopy) {}
let a = (NoCopy,);
let b = (5,);
let five: fn() -> u8 = || 5;
let num = 10;
partial!(foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), _);
partial!(foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), _,);
partial!(foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), a.clone().0,);
partial!(foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), a.clone().0);
partial!(move foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), _);
partial!(move foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), _,);
let s = a.clone();
partial!(move foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), s.clone().0,);
let s = a.clone();
partial!(move foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), s.clone().0);
let s = a;
partial!(move foo => 2, _, num, {stringify!(boo); 2}, b.0, five(), s.0);
}