use std::marker::PhantomData;
use crate::{
access::{Access, AccessError, FromAccess},
views::IndexAddress,
};
#[derive(Debug)]
pub struct Lazy<T, I> {
access: T,
address: IndexAddress,
_index: PhantomData<I>,
}
impl<T, I> FromAccess<T> for Lazy<T, I>
where
T: Access,
I: FromAccess<T>,
{
fn from_access(access: T, addr: IndexAddress) -> Result<Self, AccessError> {
Ok(Self {
access,
address: addr,
_index: PhantomData,
})
}
}
impl<T, I> Lazy<T, I>
where
T: Access,
I: FromAccess<T>,
{
pub fn get(&self) -> I {
self.try_get()
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
pub fn try_get(&self) -> Result<I, AccessError> {
I::from_access(self.access.clone(), self.address.clone())
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use super::{FromAccess, Lazy};
use crate::{access::AccessErrorKind, Database, IndexType, ListIndex, MapIndex, TemporaryDB};
#[test]
fn lazy_initialization() {
let db = TemporaryDB::new();
let fork = db.fork();
{
let lazy_index: Lazy<_, ListIndex<_, u64>> =
Lazy::from_access(&fork, "lazy".into()).unwrap();
lazy_index.get().extend(vec![1, 2, 3]);
assert_eq!(lazy_index.get().len(), 3);
lazy_index.get().push(4);
}
db.merge_sync(fork.into_patch()).unwrap();
let snapshot = db.snapshot();
let lazy_index: Lazy<_, ListIndex<_, u64>> =
Lazy::from_access(&snapshot, "lazy".into()).unwrap();
assert_eq!(
lazy_index.get().iter().collect::<Vec<_>>(),
vec![1, 2, 3, 4]
);
let bogus: Lazy<_, MapIndex<_, u64, String>> =
Lazy::from_access(&snapshot, "lazy".into()).unwrap();
assert_matches!(
bogus.try_get().unwrap_err().kind,
AccessErrorKind::WrongIndexType {
actual: IndexType::List,
..
}
)
}
}