use crate::{
Db, DbHandle, db::START_VERSION, define_input, define_intermediate, impl_storage,
storage::SingletonStorage,
};
#[derive(Default)]
struct SafeDiv {
numerator: SingletonStorage<Numerator>,
denominator: SingletonStorage<Denominator>,
division: SingletonStorage<Division>,
denominator_is_0: SingletonStorage<DenominatorIs0>,
result: SingletonStorage<Result>,
}
impl_storage!(SafeDiv,
numerator: Numerator,
denominator: Denominator,
division: Division,
denominator_is_0: DenominatorIs0,
result: Result,
);
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
struct Numerator;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
struct Denominator;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
struct Division;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
struct DenominatorIs0;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
struct Result;
define_input!(0, Numerator -> i32, SafeDiv);
define_input!(1, Denominator -> i32, SafeDiv);
define_intermediate!(2, Division -> i32, SafeDiv, |_, handle: &DbHandle<SafeDiv>| {
println!("division");
let r = handle.get(Numerator) / handle.get(Denominator);
println!("division = {r}");
r
});
define_intermediate!(3, DenominatorIs0 -> bool, SafeDiv, |_, handle: &DbHandle<SafeDiv>| {
println!("denominator is 0");
let r = handle.get(Denominator) == 0;
println!("denominator is 0 = {r}");
r
});
define_intermediate!(4, Result -> i32, SafeDiv, |_, handle: &DbHandle<SafeDiv>| {
println!("result");
let r = if handle.get(DenominatorIs0) {
0
} else {
handle.get(Division)
};
println!("result = {r}");
r
});
type SafeDivDb = Db<SafeDiv>;
#[test]
fn from_scratch() {
let mut db = SafeDivDb::new();
db.update_input(Numerator, 6);
db.update_input(Denominator, 0);
assert_eq!(0i32, db.get(Result));
}
#[test]
fn dynamic_dependency_not_run() {
let mut db = SafeDivDb::new();
db.update_input(Numerator, 6);
db.update_input(Denominator, 2);
assert_eq!(db.version(), START_VERSION + 2);
assert_eq!(3i32, db.get(Result));
println!("\n");
db.update_input(Denominator, 0);
assert_eq!(db.version(), START_VERSION + 3);
assert_eq!(0i32, db.get(Result));
}
#[test]
fn dynamic_dependency_removed() {
let mut db = SafeDivDb::new();
db.update_input(Numerator, 6);
db.update_input(Denominator, 2);
assert_eq!(db.get(Result), 3);
let divide_changed_version = db.version();
println!("Re-running with denominator = 0");
db.update_input(Denominator, 0);
assert_eq!(db.get(Result), 0);
let divide0_version = db.version();
db.with_cell_data(&Result, |result_cell| {
let result_last_verified = result_cell.last_verified_version;
let result_last_updated = result_cell.last_updated_version;
assert_eq!(result_last_verified, divide0_version);
assert_eq!(result_last_updated, divide0_version);
});
println!("\nSetting numerator = 12 now");
db.update_input(Numerator, 12);
assert!(db.get(DenominatorIs0));
assert!(!db.is_stale(&Result));
db.with_cell_data(&Division, |division_cell| {
let division_last_verified = division_cell.last_verified_version;
let division_last_updated = division_cell.last_updated_version;
assert_eq!(division_last_verified, divide_changed_version);
assert_eq!(division_last_updated, divide_changed_version);
});
}