use lazily::Context;
use std::cell::Cell;
#[test]
fn slot_computes_on_first_access() {
let ctx = Context::new();
let slot = ctx.slot(|_ctx| {
42
});
assert_eq!(ctx.get(&slot), 42);
}
#[test]
fn slot_caches_value() {
thread_local! {
static CACHE_COUNT: Cell<u32> = const { Cell::new(0) };
}
CACHE_COUNT.with(|c| c.set(0));
let ctx = Context::new();
let slot = ctx.slot(|_ctx| {
CACHE_COUNT.with(|c| c.set(c.get() + 1));
42
});
assert_eq!(ctx.get(&slot), 42);
assert_eq!(ctx.get(&slot), 42);
assert_eq!(ctx.get(&slot), 42);
CACHE_COUNT.with(|c| assert_eq!(c.get(), 1, "compute should only be called once"));
}
#[test]
fn cell_get_returns_initial_value() {
let ctx = Context::new();
let counter = ctx.cell(10i32);
assert_eq!(ctx.get_cell(&counter), 10);
}
#[test]
fn cell_set_updates_value() {
let ctx = Context::new();
let counter = ctx.cell(0i32);
ctx.set_cell(&counter, 5);
assert_eq!(ctx.get_cell(&counter), 5);
}
#[test]
fn cell_set_same_value_no_invalidation() {
thread_local! {
static SAME_COUNT: Cell<u32> = const { Cell::new(0) };
}
SAME_COUNT.with(|c| c.set(0));
let ctx = Context::new();
let counter = ctx.cell(5i32);
let doubled = ctx.slot(move |ctx| {
SAME_COUNT.with(|c| c.set(c.get() + 1));
ctx.get_cell(&counter) * 2
});
assert_eq!(ctx.get(&doubled), 10);
SAME_COUNT.with(|c| assert_eq!(c.get(), 1));
ctx.set_cell(&counter, 5);
assert!(
ctx.is_set(&doubled),
"slot should still be cached when cell value unchanged"
);
assert_eq!(ctx.get(&doubled), 10);
SAME_COUNT.with(|c| assert_eq!(c.get(), 1, "compute should not be called again"));
}
#[test]
fn cell_change_clears_dependent_slot() {
let ctx = Context::new();
let counter = ctx.cell(0i32);
let doubled = ctx.slot(move |ctx| ctx.get_cell(&counter) * 2);
assert_eq!(ctx.get(&doubled), 0);
ctx.set_cell(&counter, 5);
assert_eq!(ctx.get(&doubled), 10);
}
#[test]
fn api_style_example() {
let ctx = Context::new();
let counter = ctx.cell(0i32);
let doubled = ctx.slot(move |ctx| {
let val = ctx.get_cell(&counter);
val * 2
});
assert_eq!(ctx.get(&doubled), 0);
ctx.set_cell(&counter, 5);
assert_eq!(ctx.get(&doubled), 10); }
#[test]
fn dependency_chain_clears_transitively() {
let ctx = Context::new();
let a = ctx.cell(1i32);
let b = ctx.slot(move |ctx| ctx.get_cell(&a) + 10);
let c = ctx.slot(move |ctx| ctx.get(&b) + 100);
assert_eq!(ctx.get(&c), 111);
ctx.set_cell(&a, 2);
assert_eq!(ctx.get(&c), 112); }
#[test]
fn diamond_dependency() {
let ctx = Context::new();
let a = ctx.cell(1i32);
let b = ctx.slot(move |ctx| ctx.get_cell(&a) + 1);
let c = ctx.slot(move |ctx| ctx.get_cell(&a) + 2);
let d = ctx.slot(move |ctx| ctx.get(&b) + ctx.get(&c));
assert_eq!(ctx.get(&d), 5);
ctx.set_cell(&a, 10);
assert_eq!(ctx.get(&d), 23); }
#[test]
fn lazy_recomputation() {
thread_local! {
static LAZY_COUNT: Cell<u32> = const { Cell::new(0) };
}
LAZY_COUNT.with(|c| c.set(0));
let ctx = Context::new();
let a = ctx.cell(1i32);
let b = ctx.slot(move |ctx| {
LAZY_COUNT.with(|c| c.set(c.get() + 1));
ctx.get_cell(&a) * 2
});
assert_eq!(ctx.get(&b), 2);
LAZY_COUNT.with(|c| assert_eq!(c.get(), 1));
ctx.set_cell(&a, 5);
LAZY_COUNT.with(|c| assert_eq!(c.get(), 1, "should not recompute on invalidation"));
assert!(!ctx.is_set(&b), "slot should be cleared after cell change");
assert_eq!(ctx.get(&b), 10);
LAZY_COUNT.with(|c| assert_eq!(c.get(), 2, "should recompute on access"));
}
#[test]
fn multiple_cell_dependencies() {
let ctx = Context::new();
let x = ctx.cell(3i32);
let y = ctx.cell(4i32);
let sum = ctx.slot(move |ctx| ctx.get_cell(&x) + ctx.get_cell(&y));
assert_eq!(ctx.get(&sum), 7);
ctx.set_cell(&x, 10);
assert_eq!(ctx.get(&sum), 14);
ctx.set_cell(&y, 20);
assert_eq!(ctx.get(&sum), 30);
}
#[test]
fn slot_depending_on_slot() {
let ctx = Context::new();
let a = ctx.cell(2i32);
let b = ctx.slot(move |ctx| ctx.get_cell(&a) * 3);
let c = ctx.slot(move |ctx| ctx.get(&b) + 1);
assert_eq!(ctx.get(&c), 7);
ctx.set_cell(&a, 10);
assert_eq!(ctx.get(&c), 31); }
#[test]
fn works_with_string_types() {
let ctx = Context::new();
let name = ctx.cell("world".to_string());
let greeting = ctx.slot(move |ctx| format!("hello, {}!", ctx.get_cell(&name)));
assert_eq!(ctx.get(&greeting), "hello, world!");
ctx.set_cell(&name, "rust".to_string());
assert_eq!(ctx.get(&greeting), "hello, rust!");
}