#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[macro_export]
macro_rules! compose_expr {
() => {};
($expr:expr) => { $expr };
($head:expr, $($tail:expr),+) => { $head($crate::compose_expr!($($tail),+)) };
($first:expr => $second:expr) => { $second($first) };
($first:expr => $second:expr => $($tail:expr)=>+) => {
$crate::compose_expr!($second($first) => $($tail)=>+)
}
}
#[macro_export]
macro_rules! compose_fn {
() => { |x| x };
($($fns:expr),+) => { |x| $crate::compose_expr!($($fns),+, x) };
($($fns:expr)=>+) => { |x| $crate::compose_expr!(x => $($fns)=>+) };
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expr_right_to_left() {
let composition = |x| compose_expr!(x);
assert_eq!(composition(1), 1);
let composition = |x| compose_expr!(|x| x + 1, x);
assert_eq!(composition(1), 2);
let composition = |x| compose_expr!(|x| x + 1, |x| x * 2, x);
assert_eq!(composition(1), 3);
let composition = |x| compose_expr!(|x| x * 2, |x| x + 1, x);
assert_eq!(composition(1), 4);
}
#[test]
fn expr_left_to_right() {
let composition = |x| compose_expr!(x);
assert_eq!(composition(1), 1);
let composition = |x| compose_expr!(x => |x| x + 1);
assert_eq!(composition(1), 2);
let composition = |x| compose_expr!(x => |x| x * 2 => |x| x + 1);
assert_eq!(composition(1), 3);
let composition = |x| compose_expr!(x => |x| x + 1 => |x| x * 2);
assert_eq!(composition(1), 4);
}
#[test]
fn fn_right_to_left() {
let composition = compose_fn!();
assert_eq!(composition(1), 1);
let composition = compose_fn!(|x| x + 1);
assert_eq!(composition(1), 2);
let composition = compose_fn!(|x| x + 1, |x| x * 2);
assert_eq!(composition(1), 3);
let composition = compose_fn!(|x| x * 2, |x| x + 1);
assert_eq!(composition(1), 4);
}
#[test]
fn fn_left_to_right() {
let composition = compose_fn!();
assert_eq!(composition(1), 1);
let composition = compose_fn!(|x| x + 1);
assert_eq!(composition(1), 2);
let composition = compose_fn!( |x| x * 2 => |x| x + 1);
assert_eq!(composition(1), 3);
let composition = compose_fn!( |x| x + 1 => |x| x * 2);
assert_eq!(composition(1), 4);
}
#[test]
#[cfg(feature = "std")]
fn advanced() {
fn plus_one(x: i32) -> i32 {
x + 1
}
fn times_two(x: i32) -> i32 {
x * 2
}
fn to_string(x: i32) -> String {
x.to_string()
}
let composition = compose_fn!(to_string, plus_one, times_two);
assert_eq!(composition(17), "35");
let composition = compose_fn!(times_two => plus_one => to_string);
assert_eq!(composition(17), "35");
}
}