use mini_rx::*;
use test_log::test;
use std::cell::{Cell, RefCell};
#[test]
fn test_rx() {
let side_effect = Cell::new(1);
let mut g = RxDAG::new();
let rx = g.new_var(1);
let crx = g.new_crx(move |g| *rx.get(g) * 2);
let side_effect_ref = &side_effect;
g.run_crx(move |g| {
side_effect_ref.set(side_effect_ref.get() + *crx.get(g));
});
assert_eq!(rx.get(g.stale()), &1);
assert_eq!(crx.get(g.stale()), &2);
assert_eq!(side_effect.get(), 3);
rx.set(&g, 2);
assert_eq!(rx.get(g.stale()), &1);
assert_eq!(crx.get(g.stale()), &2);
assert_eq!(side_effect.get(), 3);
g.recompute();
assert_eq!(rx.get(g.stale()), &2);
assert_eq!(crx.get(g.stale()), &4);
assert_eq!(side_effect.get(), 7);
rx.set(&g, 4);
assert_eq!(rx.get(g.stale()), &2);
assert_eq!(crx.get(g.stale()), &4);
assert_eq!(side_effect.get(), 7);
g.recompute();
assert_eq!(rx.get(g.stale()), &4);
assert_eq!(crx.get(g.stale()), &8);
assert_eq!(side_effect.get(), 15);
}
#[test]
fn test_rx_modify() {
let mut g = RxDAG::new();
let rx = g.new_var(1);
let crx = g.new_crx(move |g| *rx.get(g) * 2);
let side_effect = Cell::new(1);
let side_effect2 = &side_effect;
g.run_crx(move |g| {
side_effect2.set(side_effect2.get() + crx.get(g));
});
assert_eq!(rx.get(g.now()), &1);
assert_eq!(crx.get(g.now()), &2);
assert_eq!(side_effect.get(), 3);
rx.modify(&g, |g| g + 3);
rx.modify(&g, |g| g + 5);
assert_eq!(rx.get(g.now()), &9);
assert_eq!(crx.get(g.now()), &18);
assert_eq!(side_effect.get(), 21);
drop(g);
}
#[test]
fn test_rx_multiple_inputs_outputs() {
let mut g = RxDAG::new();
let rx = g.new_var(1);
let rx2 = g.new_var(2);
let rx3 = g.new_var(vec![3, 4]);
{
let crx = g.new_crx(move |g| vec![*rx.get(g) * 10, *rx2.get(g) * 10]);
let crx2 = g.new_crx(move |g| {
let mut vec = Vec::new();
vec.push(*rx.get(g));
for elem in rx3.get(g).iter().copied() {
vec.push(elem)
}
for elem in crx.get(g).iter().copied() {
vec.push(elem)
}
vec
});
let (crx3_1, crx3_2) = g.new_crx2(move |g| {
let vec = crx.get(g);
(vec[0] * 10, vec[1] * 10)
});
let (crx4_1, crx4_2, crx4_3) = g.new_crx3(move |g| {
let v2 = *rx.get(g);
let v3 = *crx3_2.get(g);
let v4 = rx3.get(g)[0];
(v2, v3, v4 * 100)
});
assert_eq!(rx.get(g.now()), &1);
assert_eq!(rx2.get(g.now()), &2);
assert_eq!(rx3.get(g.now()), &vec![3, 4]);
assert_eq!(crx.get(g.now()), &vec![10, 20]);
assert_eq!(crx2.get(g.now()), &vec![1, 3, 4, 10, 20]);
assert_eq!(crx3_1.get(g.now()), &100);
assert_eq!(crx3_2.get(g.now()), &200);
assert_eq!(crx4_1.get(g.now()), &1);
assert_eq!(crx4_2.get(g.now()), &200);
assert_eq!(crx4_3.get(g.now()), &300);
rx.set(&g, 5);
rx2.set(&g, 6);
rx3.set(&g, vec![7, 8, 9]);
g.recompute();
assert_eq!(rx.get(g.now()), &5);
assert_eq!(rx2.get(g.now()), &6);
assert_eq!(rx3.get(g.now()), &vec![7, 8, 9]);
assert_eq!(crx.get(g.now()), &vec![50, 60]);
assert_eq!(crx2.get(g.now()), &vec![5, 7, 8, 9, 50, 60]);
assert_eq!(crx3_1.get(g.now()), &500);
assert_eq!(crx3_2.get(g.now()), &600);
assert_eq!(crx4_1.get(g.now()), &5);
assert_eq!(crx4_2.get(g.now()), &600);
assert_eq!(crx4_3.get(g.now()), &700);
}
}
#[test]
fn test_drx_split() {
let mut g = RxDAG::new();
let rx = g.new_var(vec![1, 2, 3]);
{
let drx0 = rx.derive_using_clone(|x| &x[0], |x, new| {
x[0] = new;
});
let drx1 = rx.derive_using_clone(|x| &x[1], |x, new| {
x[1] = new;
});
let drx2 = rx.derive_using_clone(|x| &x[2], |x, new| {
x[2] = new;
});
assert_eq!(drx0.get(g.now()), &1);
assert_eq!(drx1.get(g.now()), &2);
assert_eq!(drx2.get(g.now()), &3);
drx0.set(&g, 2);
drx1.set(&g, 3);
drx2.set(&g, 4);
}
assert_eq!(rx.get(g.now()), &vec![2, 3, 4]);
}
#[test]
fn test_crx() {
let mut g = RxDAG::new();
let rx = g.new_var(vec![1, 2, 3]);
{
let crx = g.new_crx(move |g| rx.get(g)[0] * 2);
let crx2 = g.new_crx(move |g| *crx.get(g) + rx.get(g)[1] * 10);
let crx3 = g.new_crx(move |g| crx2.get(g).to_string());
assert_eq!(*crx.get(g.now()), 2);
assert_eq!(*crx2.get(g.now()), 22);
assert_eq!(&*crx3.get(g.now()), "22");
rx.set(&g, vec![2, 3, 4]);
assert_eq!(*crx.get(g.now()), 4);
assert_eq!(*crx2.get(g.now()), 34);
assert_eq!(&*crx3.get(g.now()), "34");
rx.set(&g, vec![3, 4, 5]);
assert_eq!(*crx.get(g.now()), 6);
assert_eq!(*crx2.get(g.now()), 46);
assert_eq!(&*crx3.get(g.now()), "46");
}
}
#[test]
fn test_readme() {
let side_effect = Cell::new(0);
let side_effect2 = RefCell::new(String::new());
let mut g = RxDAG::new();
let var1 = g.new_var(1);
let var2 = g.new_var("hello");
assert_eq!(var1.get(g.now()), &1);
assert_eq!(var2.get(g.now()), &"hello");
var1.set(&g, 2);
var2.set(&g, "world");
assert_eq!(var1.get(g.now()), &2);
assert_eq!(var2.get(g.now()), &"world");
let crx1 = g.new_crx(move |g| var1.get(g) * 2);
let crx2 = g.new_crx(move |g| format!("{}-{}", var2.get(g), crx1.get(g) * 2));
let (crx3, crx4) = g.new_crx2(move |g| var2.get(g).split_at(3));
assert_eq!(crx1.get(g.now()), &4);
assert_eq!(crx2.get(g.now()), &"world-8");
assert_eq!(crx3.get(g.now()), &"wor");
assert_eq!(crx4.get(g.now()), &"ld");
var1.set(&g, 3);
var2.set(&g, &"rust");
assert_eq!(crx1.get(g.now()), &6);
assert_eq!(crx2.get(g.now()), &"rust-12");
assert_eq!(crx3.get(g.now()), &"rus");
assert_eq!(crx4.get(g.now()), &"t");
let var3 = g.new_var(Vec::from("abc"));
let side_effect_ref = &side_effect;
let side_effect_ref2 = &side_effect2;
g.run_crx(move |g| {
side_effect_ref.set(side_effect_ref.get() + var1.get(g));
side_effect_ref2.borrow_mut().push_str(&String::from_utf8_lossy(var3.get(g)));
});
assert_eq!(side_effect.get(), 3);
assert_eq!(&*side_effect2.borrow(), &"abc");
var1.set(&g, 4);
g.recompute();
assert_eq!(side_effect.get(), 7);
assert_eq!(&*side_effect2.borrow(), &"abcabc");
var3.set(&g, Vec::from("xyz"));
assert_eq!(side_effect.get(), 7);
assert_eq!(&*side_effect2.borrow(), &"abcabc");
g.recompute();
assert_eq!(side_effect.get(), 11);
assert_eq!(&*side_effect2.borrow(), &"abcabcxyz");
var2.set(&g, "rust-lang");
g.recompute();
assert_eq!(side_effect.get(), 11);
assert_eq!(&*side_effect2.borrow(), &"abcabcxyz");
assert_eq!(crx2.get(g.now()), &"rust-lang-16");
let dvar = var3.derive_using_clone(|x| &x[0], |x, char| {
x[0] = char;
});
assert_eq!(dvar.get(g.now()), &b'x');
dvar.set(&g, b'b');
assert_eq!(dvar.get(g.now()), &b'b');
assert_eq!(var3.get(g.now()), &b"byz");
dvar.set(&g, b'f');
assert_eq!(dvar.get(g.now()), &b'f');
assert_eq!(var3.get(g.now()), &b"fyz");
assert_eq!(&*side_effect2.borrow(), &"abcabcxyzbyzfyz");
}
#[test]
fn stream_like() {
let stream = RefCell::new(Vec::new());
let stream_ref = &stream;
let input1 = vec![1, 2, 3];
let input2 = vec![0.5, 0.4, 0.8];
let mut g = RxDAG::new();
let var1 = g.new_var(0);
let var2 = g.new_var(0.0);
let crx = g.new_crx(move |g| *var1.get(g) as f64 + *var2.get(g));
g.run_crx(move |g| {
stream_ref.borrow_mut().push(*crx.get(g));
});
assert_eq!(&*stream.borrow(), &vec![0.0]);
for (a, b) in input1.iter().zip(input2.iter()) {
var1.set(&g, *a);
var2.set(&g, *b);
g.recompute();
}
assert_eq!(&*stream.borrow(), &vec![0.0, 1.5, 2.4, 3.8]);
}