#![deny(warnings)]
#[macro_export]
macro_rules! __internal_pipe_fun {
(&, $ret:expr) => {
&$ret
};
((as $typ:ty), $ret:expr) => {
$ret as $typ
};
(($funs_head:tt $(:: $funs_tail:tt)* ($($arg:expr),*)), $ret:expr) => {
$funs_head $(:: $funs_tail)* ($ret $(,$arg)*)
};
(($fun:ident!($($arg:expr),*)), $ret:expr) => {
$fun!($ret $(,$arg)*)
};
(($fun:expr), $ret:expr) => {
$fun($ret)
};
($fun:path, $ret:expr) => {
$fun($ret)
};
(!, $fun:ident, $ret:expr) => {
$fun!($ret)
}
}
#[macro_export]
macro_rules! pipe {
($head:tt $(|> $funs_head:tt $(:: $funs_tail:tt)*)+) => {
{
let ret = $head;
$(
let ret = $crate::__internal_pipe_fun!($funs_head $(:: $funs_tail)*, ret);
)+
ret
}
}
}
#[macro_export]
macro_rules! pipe_res {
($head:tt $(|> $funs_head:tt $(:: $funs_tail:tt)*)+) => {
{
let ret = Ok($head);
$(
let ret = match ret {
Ok(x) => $crate::__internal_pipe_fun!($funs_head $(:: $funs_tail)*, x),
_ => ret
};
)*
ret
}
};
}
#[macro_export]
macro_rules! pipe_opt {
($head:tt $(|> $funs_head:tt $(:: $funs_tail:tt)*)+) => {
{
let ret = None;
$(
let ret = match ret {
None => $crate::__internal_pipe_fun!($funs_head $(:: $funs_tail)*, $head),
_ => ret
};
)*
ret
}
};
}
#[cfg(test)]
mod test_pipe_opt {
fn times2(a: u32) -> Option<u32> {
return Some(a * 2);
}
fn nope(_a: u32) -> Option<u32> {
return None;
}
#[test]
fn accepts_options() {
let ret = pipe_opt!(
4
|> times2
);
assert_eq!(ret, Some(8));
}
#[test]
fn accepts_unwrap() {
let ret = pipe_opt!(
4
|> times2
)
.unwrap();
assert_eq!(ret, 8);
}
#[test]
fn exits_early() {
let ret = pipe_opt!(
4
|> times2
|> times2
|> times2
);
assert_eq!(ret, Some(8));
}
#[test]
fn goes_until_some() {
let ret = pipe_opt!(
4
|> nope
|> nope
|> (|_i: u32| None)
|> times2
|> nope
);
assert_eq!(ret, Some(8));
}
#[test]
fn ends_with_none() {
let ret = pipe_opt!(
4
|> nope
|> nope
|> (|_i| None)
|> nope
);
assert_eq!(ret, None);
}
}
#[cfg(test)]
mod test_pipe_res {
fn times2(a: u32) -> Result<u32, String> {
return Ok(a * 2);
}
fn fail_if_over_4(a: u32) -> Result<u32, String> {
if a > 4 {
return Err("This number is larger than four".to_string());
}
return Ok(a);
}
#[test]
fn accepts_results() {
let ret = pipe_res!(
4
|> times2
);
assert_eq!(ret, Ok(8));
}
#[test]
fn accepts_unwrap() {
let ret = pipe_res!(
4
|> times2
)
.unwrap();
assert_eq!(ret, 8);
}
#[test]
fn chains_result_values() {
let ret = pipe_res!(
4
|> times2
|> times2
|> times2
);
assert_eq!(ret, Ok(32));
}
#[test]
fn exits_early() {
let ret = pipe_res!(
4
|> times2
|> fail_if_over_4
|> times2
|> times2
);
assert_eq!(ret, Err("This number is larger than four".to_string()));
}
}
#[cfg(test)]
mod test_pipe {
fn times2(a: u32) -> u32 {
return a * 2;
}
fn times(a: u32, b: u32, c: u32) -> u32 {
return a * b * c;
}
#[test]
fn test_int() {
let multiply = |i: u32| i * 2;
let ret = pipe!(
4
|> times2
|> (|i: u32| i * 2)
|> multiply
|> (times(100, 10))
);
assert_eq!(ret, 32000);
}
#[test]
fn test_string() {
let ret = pipe!(
"abcd"
|> str::len
|> (as u32)
|> times2
|> (times(100, 10))
|> &
|> u32::to_string
);
assert_eq!(ret, times(times2("abcd".len() as u32), 100, 10).to_string());
assert_eq!(ret, "8000");
}
}