use std::collections::HashMap;
use trusty_common::memory_core::palace::Drawer;
use uuid::Uuid;
use super::mapping::{
MappedMemory, HASH_TAG_PREFIX, PENDING_TAG_PREFIX, SOURCE_TAG_PREFIX, STORE_TAG_PREFIX,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImportedDrawer {
pub drawer_id: Uuid,
pub hash: Option<String>,
pub store: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemoryPlan {
New,
Unchanged(Uuid),
Changed(Uuid),
Resume(Uuid),
SharedId(Uuid),
}
#[derive(Debug, Default)]
pub struct Ledger {
by_key: HashMap<String, ImportedDrawer>,
pending: HashMap<String, Uuid>,
}
impl Ledger {
pub fn from_drawers<'a>(drawers: impl IntoIterator<Item = &'a Drawer>) -> Self {
let mut ledger = Self::default();
for drawer in drawers {
let tag = |prefix: &str| {
drawer
.tags
.iter()
.find_map(|t| t.strip_prefix(prefix))
.map(str::to_string)
};
match tag(SOURCE_TAG_PREFIX) {
Some(key) => {
ledger
.by_key
.entry(format!("kuzu-memory/{key}"))
.or_insert(ImportedDrawer {
drawer_id: drawer.id,
hash: tag(HASH_TAG_PREFIX),
store: tag(STORE_TAG_PREFIX),
});
}
None => {
if let Some(id) = tag(PENDING_TAG_PREFIX) {
ledger.pending.entry(id).or_insert(drawer.id);
}
}
}
}
ledger
}
pub fn get(&self, source_key: &str) -> Option<&ImportedDrawer> {
self.by_key.get(source_key)
}
pub fn plan(&self, memory: &MappedMemory, store_is_live: &dyn Fn(&str) -> bool) -> MemoryPlan {
match self.get(&memory.source_key) {
None => match self.pending.get(&memory.memory_id) {
Some(id) => MemoryPlan::Resume(*id),
None => MemoryPlan::New,
},
Some(d) if d.hash.as_deref() == Some(memory.hash.as_str()) => {
MemoryPlan::Unchanged(d.drawer_id)
}
Some(d) => match d.store.as_deref() {
Some(other) if other != memory.store && store_is_live(other) => {
MemoryPlan::SharedId(d.drawer_id)
}
_ => MemoryPlan::Changed(d.drawer_id),
},
}
}
pub fn len(&self) -> usize {
self.by_key.len()
}
pub fn is_empty(&self) -> bool {
self.by_key.is_empty()
}
}