Skip to main content

salamander/agent/
kv.rs

1//! `KvProjection`: a `BTreeMap<String, Vec<u8>>` folded over `Put`/`Delete`
2//! events. The engine-correctness workhorse; used by the crash harness.
3//!
4//! Kept in the `agent` module for now (Phase 1.5 spec, WP-1 step 4): its
5//! `Put`/`Delete` live in `EventBody`, so it folds `EventBody` like the
6//! session view does. The query layer's `IndexedView` (WP-3) supersedes it
7//! as the general-purpose, payload-agnostic store.
8
9use std::collections::BTreeMap;
10
11use super::EventBody;
12use crate::event::Event;
13use crate::projection::Projection;
14
15/// A last-write-wins key/value store folded from [`EventBody::Put`] and
16/// [`EventBody::Delete`] events. The simplest built-in projection; the
17/// query layer's [`crate::IndexedView`] is the general-purpose store.
18#[derive(Debug, Default)]
19pub struct KvProjection {
20    state: BTreeMap<String, Vec<u8>>,
21    cursor: u64,
22}
23
24impl Projection for KvProjection {
25    type Body = EventBody;
26    type State = BTreeMap<String, Vec<u8>>;
27
28    fn apply(&mut self, event: &Event<EventBody>) {
29        match &event.body {
30            EventBody::Put { key, value } => {
31                self.state.insert(key.clone(), value.clone());
32            }
33            EventBody::Delete { key } => {
34                self.state.remove(key);
35            }
36            _ => {}
37        }
38        self.cursor = event.offset + 1;
39    }
40
41    fn cursor(&self) -> u64 {
42        self.cursor
43    }
44
45    fn state(&self) -> &Self::State {
46        &self.state
47    }
48}