use inc_complete::{
Db, DbHandle, StorageFor, define_input, define_intermediate, impl_storage,
storage::{HashMapStorage, TreeIndexStorage},
};
use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, Deserialize)]
struct StorageWithoutAsPlusBs {
strings: HashMapStorage<Strings>,
count_as: TreeIndexStorage<CountAs>,
count_bs: HashMapStorage<CountBs>,
}
impl_storage!(StorageWithoutAsPlusBs,
strings: Strings,
count_as: CountAs,
count_bs: CountBs,
);
#[derive(Default, Serialize, Deserialize)]
struct Storage {
strings: HashMapStorage<Strings>,
count_as: TreeIndexStorage<CountAs>,
count_bs: HashMapStorage<CountBs>,
#[serde(default)]
as_plus_bs: HashMapStorage<AsPlusBs>,
}
impl_storage!(Storage,
strings: Strings,
count_as: CountAs,
count_bs: CountBs,
as_plus_bs: AsPlusBs,
);
define_input!(0, Strings -> String, Storage | StorageWithoutAsPlusBs);
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
struct Strings {
name: String,
}
define_intermediate!(1, CountAs -> usize, Storage | StorageWithoutAsPlusBs, count_as_impl);
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Ord, PartialOrd)]
struct CountAs {
name: String,
}
define_intermediate!(2, CountBs -> usize, Storage | StorageWithoutAsPlusBs, count_bs_impl);
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
struct CountBs {
name: String,
}
define_intermediate!(3, AsPlusBs -> usize, Storage | StorageWithoutAsPlusBs, as_plus_bs_impl);
#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
struct AsPlusBs {
name: String,
}
fn count_as_impl<S: inc_complete::Storage + StorageFor<Strings>>(
this: &CountAs,
db: &DbHandle<S>,
) -> usize {
let input = db.get(Strings {
name: this.name.clone(),
});
input.chars().filter(|c| *c == 'a').count()
}
fn count_bs_impl<S: inc_complete::Storage + StorageFor<Strings>>(
this: &CountBs,
db: &DbHandle<S>,
) -> usize {
let input = db.get(Strings {
name: this.name.clone(),
});
input.chars().filter(|c| *c == 'b').count()
}
fn as_plus_bs_impl<S>(params: &AsPlusBs, db: &DbHandle<S>) -> usize
where
S: inc_complete::Storage + StorageFor<Strings> + StorageFor<CountAs> + StorageFor<CountBs>,
{
let name = ¶ms.name;
let a_count = db.get(CountAs { name: name.clone() });
let b_count = db.get(CountBs { name: name.clone() });
a_count + b_count
}
#[test]
fn still_cached_after_serialize() {
let mut db = Db::<Storage>::new();
let half = "50%".to_string();
db.update_input(
Strings { name: half.clone() },
"ababababab ababababab".to_string(),
);
assert_eq!(db.get(CountAs { name: half.clone() }), 10);
let serialized = serde_json::to_string(&db).unwrap();
let new_db: Db<Storage> = serde_json::from_str(&serialized).unwrap();
assert!(!new_db.is_stale(&CountAs { name: half.clone() }));
assert!(new_db.is_stale(&AsPlusBs { name: half.clone() }));
assert_eq!(new_db.get(AsPlusBs { name: half.clone() }), 20);
assert!(!new_db.is_stale(&AsPlusBs { name: half.clone() }));
assert!(db.is_stale(&AsPlusBs { name: half.clone() }));
}
#[test]
fn extend_preexisting_db_from_end() {
let mut db = Db::<StorageWithoutAsPlusBs>::new();
let half = "50%".to_string();
db.update_input(
Strings { name: half.clone() },
"ababababab ababababab".to_string(),
);
assert_eq!(db.get(CountAs { name: half.clone() }), 10);
assert_eq!(db.get(CountBs { name: half.clone() }), 10);
let serialized = serde_json::to_string(&db).unwrap();
let extended_db: Db<Storage> = serde_json::from_str(&serialized).unwrap();
assert!(!extended_db.is_stale(&CountAs { name: half.clone() }));
assert!(!extended_db.is_stale(&CountBs { name: half.clone() }));
assert!(extended_db.is_stale(&AsPlusBs { name: half.clone() }));
assert_eq!(extended_db.get(AsPlusBs { name: half.clone() }), 20);
}