#![deny(missing_docs)]
pub use sum::Sum;
pub use prod::Prod;
pub use any::Any;
pub use all::All;
pub use max::Max;
pub use min::Min;
pub use vector::Vector;
pub use sift::Sift;
pub use secret::Secret;
pub use for_loop::For;
mod sum;
mod prod;
mod any;
mod all;
mod max;
mod min;
mod vector;
mod sift;
mod secret;
mod for_loop;
pub trait Lup<I, T> {
type Inner;
fn start() -> Self;
fn it(&mut self, I, T) -> bool;
fn unwrap(self) -> Self::Inner;
}
#[macro_export]
macro_rules! lup(
($sum:ty : $i:tt , $($j:tt),+ by $list:expr => $body:block) => {
lup!($sum : $i in 0..$list.len() => {
lup!($sum : $($j),* by $list[$i] => $body)
})
};
($sum:ty : $i:tt in $iter:expr , $($j:tt in $iter2:expr),+ => $body:block) => {
lup!($sum : $i in $iter => {
lup!($sum : $($j in $iter2),* => $body)
})
};
($sum:ty : $i:tt by $list:expr => $body:block) => {
lup!($sum : $i in 0..$list.len() => $body)
};
($sum:ty : $i:tt in $iter:expr => $body:block) => {{
use $crate::Lup;
let mut sum: $sum = Lup::start();
let mut iter = $iter;
while let Some($i) = iter.next() {
if !sum.it($i, $body) {break};
}
sum.unwrap()
}}
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn list() {
type Num = f32;
let list = vec![vec![vec![1.0, 2.0, 3.0]]];
let sum = lup!(Sum<Num>:
i in 0..list.len(),
j in 0..list[i].len(),
k in 0..list[i][j].len() => {
list[i][j][k]
});
assert_eq!(sum, 6.0);
let prod = lup!(Prod<Num>:
i in 0..list.len(),
j in 0..list[i].len(),
k in 0..list[i][j].len() => {
list[i][j][k]
});
assert_eq!(prod, 6.0);
let any = lup!(Any<_>: i in 0..list[0][0].len() => {
list[0][0][i] > 2.0
});
assert_eq!(any.evidence, Some(2));
let any = lup!(Any<_>:
i in 0..list.len(),
j in 0..list[i].len(),
k in 0..list[i][j].len() => {
list[i][j][k] > 2.0
});
assert_eq!(any.evidence, Some((0, 0, 2)));
let all = lup!(All<_>:
i in 0..list.len(),
j in 0..list[i].len(),
k in 0..list[i][j].len() => {
list[i][j][k] < 3.0
});
assert_eq!(all.evidence, Some((0, 0, 2)));
let comb = lup!(Any<_>:
i in 0..list.len(),
j in 0..list[i].len() => {
!lup!(All<_>: k in 0..list[i][j].len() => {
list[i][j][k] < 3.0
})
});
assert_eq!(comb.value, true);
assert_eq!(comb.evidence, Some((0, 0, 2)));
let max = lup!(Max<_, Num>:
i in 0..list.len(),
j in 0..list[i].len(),
k in 0..list[i][j].len() => {
list[i][j][k]
});
assert_eq!(max.value, 3.0);
assert_eq!(max.evidence, Some((0, 0, 2)));
let min = lup!(Min<_, Num>:
i in 0..list.len(),
j in 0..list[i].len(),
k in 0..list[i][j].len() => {
list[i][j][k]
});
assert_eq!(min.value, 1.0);
assert_eq!(min.evidence, Some((0, 0, 0)));
let comb = lup!(Any<_>:
i in 0..list.len(),
j in 0..list[i].len() => {
lup!(Max<_, f32>: k in 0..list[i][j].len() => {
list[i][j][k]
}).eq(&3.0)
});
assert_eq!(comb.value, true);
assert_eq!(comb.evidence, Some((0, 0, 2)));
}
#[test]
fn vector() {
let list = vec![[0.2, 0.3, 0.4], [0.1, 0.5, 0.7]];
let sum = lup!(Sum<[f32; 3]>: i in 0..list.len() => {list[i]});
assert_eq!(sum, [0.3, 0.8, 1.1]);
let prod = lup!(Prod<[f32; 3]>: i in 0..list.len() => {list[i]});
assert_eq!(prod, [0.020000001, 0.15, 0.28]);
let v = lup!(Vector<[f32; 4]>: i in 0..3 => {list[0][i] + list[1][i]});
assert_eq!(v, [0.3, 0.8, 1.1, 0.0]);
}
#[test]
fn sift() {
let list = lup!(Sift<Vec<f32>>: i in 0..5 => {i as f32 + 1.0});
assert_eq!(list, vec![1.0, 2.0, 3.0, 4.0, 5.0]);
let list = lup!(Sift<_>:
i in 0..3,
j in 0..3 => {
i as f32 + j as f32
});
assert_eq!(list, vec![
vec![0.0, 1.0, 2.0],
vec![1.0, 2.0, 3.0],
vec![2.0, 3.0, 4.0],
]);
let symmetric = lup!(All<_>:
i in 0..3,
j in 0..3 => {
list[i][j] == list[j][i]
});
assert_eq!(symmetric.value, true);
}
#[test]
fn short() {
let list = lup!(Sift<_>: i in 0..3, j in 0..3, k in 0..3 => {
i as f32 + j as f32 + k as f32
});
let a = lup!(Sum<_>: i, j, k by list => {list[i][j][k]});
assert_eq!(a, 81.0);
}
#[test]
fn for_loop() {
let list = vec![vec![1, 2], vec![3, 4]];
lup!(For: i, j by list => {
println!("{}", list[i][j]);
});
}
}